diff --git a/.gitignore b/.gitignore index ae8de00a8b9f..4eab35fa7fe7 100644 --- a/.gitignore +++ b/.gitignore @@ -137,7 +137,12 @@ all.config kernel/configs/android-*.cfg # vendor device tree directories -arch/arm64/boot/dts/vendor/ +#arch/arm64/boot/dts/vendor +#drivers/oneplus/ +#include/linux/oem # Tech package directories -techpack/ +#techpack/ + +# OP SLA feature +#opslalib/slalib diff --git a/Makefile b/Makefile index c240b20902bc..19e19a847839 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__ @@ -436,6 +437,12 @@ KBUILD_LDFLAGS := GCC_PLUGINS_CFLAGS := CLANG_FLAGS := +ifeq ($(filter instantnoodle%, $(OEM_TARGET_PRODUCT)),) +KBUILD_CFLAGS += -DUFS3V1 +else +KBUILD_CFLAGS += -DUFS3V0 +endif + export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE @@ -590,7 +597,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 000000000000..855132a4d23d --- /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/qcom/Makefile b/arch/arm64/boot/dts/vendor/qcom/Makefile new file mode 100755 index 000000000000..9022679a7120 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/Makefile @@ -0,0 +1,111 @@ + + dtbo-$(CONFIG_ARCH_KONA) += \ + instantnoodlep-overlay-evb.dtbo \ + instantnoodlep-overlay-t0.dtbo \ + instantnoodlep-overlay-evt1.dtbo \ + instantnoodlep-overlay-dvt.dtbo \ + instantnoodle-overlay-t0.dtbo \ + instantnoodle-overlay-evt1.dtbo \ + instantnoodle-overlay-dvt.dtbo \ + instantnoodlev-overlay-t0.dtbo \ + instantnoodlev-overlay-evt1.dtbo \ + instantnoodlev-overlay-dvt.dtbo + +instantnoodlep-overlay-evb.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodlep-overlay-t0.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodlep-overlay-evt1.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodlep-overlay-dvt.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb + +instantnoodle-overlay-t0.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodle-overlay-evt1.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodle-overlay-dvt.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb + +instantnoodlev-overlay-t0.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodlev-overlay-evt1.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +instantnoodlev-overlay-dvt.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb + + + + +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 \ + qcm4290-iot-idp-overlay.dtbo \ + qcs4290-iot-idp-overlay.dtbo \ + qcm4290-iot-idp-1gb-overlay.dtbo \ + qcm4290-iot-idp-2gb-overlay.dtbo \ + qcm4290-iot-idp-usbc-1gb-overlay.dtbo \ + qcm4290-iot-idp-usbc-2gb-overlay.dtbo \ + qcm4290-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 +qcm4290-iot-idp-overlay.dtbo-base := qcm4290.dtb +qcs4290-iot-idp-overlay.dtbo-base := qcs4290.dtb +qcm4290-iot-idp-1gb-overlay.dtbo-base := qcm4290-iot-1gb.dtb +qcm4290-iot-idp-2gb-overlay.dtbo-base := qcm4290-iot-2gb.dtb +qcm4290-iot-idp-usbc-1gb-overlay.dtbo-base := qcm4290-iot-1gb.dtb +qcm4290-iot-idp-usbc-2gb-overlay.dtbo-base := qcm4290-iot-2gb.dtb +qcm4290-iot-idp-usbc-overlay.dtbo-base := qcm4290.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 \ + qcm4290-iot-idp.dtb \ + qcs4290-iot-idp.dtb \ + qcm4290-iot-idp-1gb.dtb \ + qcm4290-iot-idp-2gb.dtb \ + qcm4290-iot-idp-usbc-1gb.dtb \ + qcm4290-iot-idp-usbc-2gb.dtb \ + qcm4290-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-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 +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 +endif + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb *.dtbo diff --git a/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4300mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4300mah.dtsi new file mode 100644 index 000000000000..6f93316f5ab9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4300mah.dtsi @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2019, 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. + */ + +qcom,OP_4300mAh { + qcom,max-voltage-uv = <4420000>; + qcom,fastchg-current-ma = <3000>; + qcom,jeita-fcc-ranges = <0 100 2500000 + 110 400 5400000 + 410 450 2500000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 110 400 4420000 + 410 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 + 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4380>; + qcom,battery-type = "OP_4300mAh"; + 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/OP-fg-batterydata-4320mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4320mah.dtsi new file mode 100644 index 000000000000..4ec453831d00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4320mah.dtsi @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2019, 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. + */ + +qcom,OP_4320mAh { + qcom,max-voltage-uv = <4420000>; + qcom,fastchg-current-ma = <3000>; + qcom,jeita-fcc-ranges = <0 100 2500000 + 110 400 5400000 + 410 450 2500000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 110 400 4420000 + 410 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 + 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4380>; + qcom,battery-type = "OP_4320mAh"; + 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/OP-fg-batterydata-4500mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4500mah.dtsi new file mode 100644 index 000000000000..adcfb8a27d57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4500mah.dtsi @@ -0,0 +1,145 @@ +/* + * Copyright (c) 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. + */ + +qcom,OP_4500mAh { + qcom,max-voltage-uv = <4420000>; + qcom,fastchg-current-ma = <3000>; + qcom,jeita-fcc-ranges = <0 100 2500000 + 110 400 5400000 + 410 450 2500000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 110 400 4420000 + 410 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 + 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4380>; + qcom,battery-type = "OP_4500mAh"; + 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/OP-fg-batterydata-4510mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4510mah.dtsi new file mode 100644 index 000000000000..e65a04daedbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/OP-fg-batterydata-4510mah.dtsi @@ -0,0 +1,145 @@ +/* + * Copyright (c) 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. + */ + +qcom,OP_4510mAh { + qcom,max-voltage-uv = <4420000>; + qcom,fastchg-current-ma = <3000>; + qcom,jeita-fcc-ranges = <0 100 2500000 + 110 400 5400000 + 410 450 2500000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 110 400 4420000 + 410 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 + 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4380>; + qcom,battery-type = "OP_4510mAh"; + 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/bengal-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-1gb.dts new file mode 100644 index 000000000000..e21f6863fe8f --- /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 000000000000..b4c7dda19003 --- /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 000000000000..29025c620ed1 --- /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 000000000000..0bffa0ead7b1 --- /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 000000000000..1932f9d7d20b --- /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 000000000000..c5b6c25a5cc8 --- /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 000000000000..16c1a0a7a340 --- /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 000000000000..afd5edcdff52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-gpu.dtsi @@ -0,0 +1,651 @@ +&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,bus-width = <32>; + 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 000000000000..f614df1a9f31 --- /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 000000000000..d272c7b4069f --- /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 000000000000..962305e27473 --- /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 000000000000..fd12308a97bb --- /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 000000000000..eef3e49bcece --- /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 000000000000..5b1e7f3b1ddd --- /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 000000000000..91c3725f222b --- /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 000000000000..95ebbd014e8a --- /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 000000000000..4b5b228289f2 --- /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 000000000000..d35e02cde4a8 --- /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 000000000000..4f2bb4c659a4 --- /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 000000000000..c9e9b2498e0a --- /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 000000000000..704385e62afe --- /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 000000000000..5c41c0d3d9a4 --- /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 000000000000..9adc20d02322 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dtsi @@ -0,0 +1,429 @@ +#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>; +}; + +&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>; + }; +}; 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 000000000000..b1e71e3dca0b --- /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-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-low-ram.dtsi new file mode 100644 index 000000000000..8179bf419f81 --- /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 000000000000..4bcd1af8b0d0 --- /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 000000000000..8f3ec92c6891 --- /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 000000000000..059d29f525ca --- /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 000000000000..1a4bfdca0386 --- /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 000000000000..8d1c093986b2 --- /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 000000000000..18858d38abfb --- /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 000000000000..c050d4bc05a6 --- /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 000000000000..ba3ca199be62 --- /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 000000000000..87c19bae131d --- /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 000000000000..b443a8490901 --- /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 000000000000..236d76f18caa --- /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 000000000000..f85652d2c6b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-sde-display.dtsi @@ -0,0 +1,241 @@ +#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 + +&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"; + }; +}; + +&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>; + }; + }; +}; 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 000000000000..72e4bc6659e0 --- /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 000000000000..e94c58e436a5 --- /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 000000000000..f0698e7f9641 --- /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 000000000000..bfc70d7808e4 --- /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 000000000000..d8a3fd1a2c5b --- /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 000000000000..f079a7764bc6 --- /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 000000000000..2e00ba31b410 --- /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 000000000000..9ae48674aa9e --- /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 000000000000..b1b060eba0aa --- /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 0x80040860>; + + 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 000000000000..d8ba915bd6d4 --- /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 000000000000..578d7158addc --- /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.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp.dts new file mode 100644 index 000000000000..a4bc2aca4c87 --- /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 000000000000..f9a2c1166b9b --- /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 100755 index 000000000000..65ac19946f1e --- /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 100755 index 000000000000..a4c93476024f --- /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 100755 index 000000000000..23c6041547f9 --- /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 100755 index 000000000000..59651a354157 --- /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 100755 index 000000000000..a407bd656a0b --- /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 100755 index 000000000000..c18b74391c18 --- /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 100755 index 000000000000..9f5be32843e1 --- /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 100755 index 000000000000..61125d0c8087 --- /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 100755 index 000000000000..8c5cc6148c5b --- /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 100755 index 000000000000..d77f337a9e3c --- /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 100755 index 000000000000..51b0babaa709 --- /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 100755 index 000000000000..e22e1f99f670 --- /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 100755 index 000000000000..0a11bea1fba7 --- /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 100755 index 000000000000..801c3feae3d7 --- /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 100755 index 000000000000..73e99b25cd8f --- /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 100755 index 000000000000..409be3f08de4 --- /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 100755 index 000000000000..fdd6c5e980f1 --- /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 100755 index 000000000000..eca2bd82ec79 --- /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 100755 index 000000000000..73a4b7bc069b --- /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 100755 index 000000000000..8f7c21b97765 --- /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 100755 index 000000000000..0e34d93ad576 --- /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 100755 index 000000000000..e8df9d4388a4 --- /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 100755 index 000000000000..ab81329df08e --- /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 100755 index 000000000000..04548caa330b --- /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 100755 index 000000000000..38cf6a0e9909 --- /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 100755 index 000000000000..a1dab4718adf --- /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 100755 index 000000000000..9e69a98cf38d --- /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 100755 index 000000000000..261a7fe65f11 --- /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 100755 index 000000000000..d42b8cc1dc9c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xr.dtsi @@ -0,0 +1,713 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash@0 { + 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-flash@1 { + 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_eye_track: qcom,camera-flash@2 { + cell-index = <2>; + compatible = "qcom,camera-flash"; + gpios = <&tlmm 22 0>, + <&tlmm 23 0>, + <&tlmm 24 0>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <0 0 0>; + gpio-req-tbl-label = "TCKING_LED_1V2_EN", + "TCKING_LED_3V3_EN", + "TCKING_LED_EN"; + gpio-req-tbl-delay = <20 20 20>; + 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 = "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 = <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>; + led-flash-src = <&led_flash_eye_track>; + 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 100755 index 000000000000..e4caa84b155a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xrfusion.dtsi @@ -0,0 +1,761 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash@0 { + 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-flash@1 { + 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_eye_track: qcom,camera-flash@2 { + cell-index = <2>; + compatible = "qcom,camera-flash"; + gpios = <&tlmm 22 0>, + <&tlmm 23 0>, + <&tlmm 24 0>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <0 0 0>; + gpio-req-tbl-label = "TCKING_LED_1V2_EN", + "TCKING_LED_3V3_EN", + "TCKING_LED_EN"; + gpio-req-tbl-delay = <20 20 20>; + 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 = "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 Right (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): Combo Mode */ + 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>; + led-flash-src = <&led_flash_eye_track>; + 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>; + }; + + /* 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 100755 index 000000000000..11dc66d57e63 --- /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/kona-oem-camera-instantnoodle.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodle.dtsi new file mode 100755 index 000000000000..df6db8a6fcda --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodle.dtsi @@ -0,0 +1,897 @@ +&pm8009_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_2_ana_active: cam_sensor_rear_2_ana_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_ana_suspend: cam_sensor_rear_2_ana_suspend { + pins = "gpio1"; + 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>; + 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_wide: 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"; + }; +}; + +&cam_cci0 { + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8009_l5>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <3000000>; + rgltr-load-current = <600000>; + }; + + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vaf-supply = <&pm8009_l6>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000>; + rgltr-max-voltage = <0 1104000 2800000>; + rgltr-load-current = <0 1200000 1200000>; + 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 = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <0 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; +/*wide camera*/ + 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_0>; + eeprom-src = <&eeprom_rear_0>; + ois-src = <&ois_rear_0>; + led-flash-src = <&led_flash_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_vaf-supply = <&pm8009_l5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2","cam_vaf", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 2800000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 3000000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; +/*ultra_camera*/ + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x3>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_1>; + led-flash-src = <&led_flash_rear_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <100000 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; + +}; + +&cam_cci1 { + + actuator_rear_1: qcom,actuator@0 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <3008000>; + rgltr-max-voltage = <3960000>; + rgltr-load-current = <100000>; + /*gpio request at sensor + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 159 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAMIF_vaf";*/ + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_2: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x03>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2"; + 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 = <19200000>; + }; +/*front camera*/ + 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_0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +/*ultra wide*/ + 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 = <0>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_2>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active + &cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend + &cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>, + <&tlmm 159 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VAF"; + 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 = <19200000>; + }; +}; + +&tlmm { + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + 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 = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + 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 = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + 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 = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + 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 = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_avdd_suspend: cam_sensor_front_avdd_suspend { + /* RESET 2 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + 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 = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + 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 */ + }; + }; + + cam_sensor_rear_0_avdd_active: cam_sensor_rear_0_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd_suspend: cam_sensor_rear_0_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_evb.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_evb.dtsi new file mode 100755 index 000000000000..86a555b6aa93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_evb.dtsi @@ -0,0 +1,872 @@ +&pm8009_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_2_dvdd_active: cam_sensor_rear_2_dvdd_active { + pins = "gpio2"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_dvdd_suspend: cam_sensor_rear_2_dvdd_suspend { + pins = "gpio2"; + function = "normal"; + power-source = <0>; + bias-pull-down; + input-disable; + }; + + cam_sensor_rear_2_ana_active: cam_sensor_rear_2_ana_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_ana_suspend: cam_sensor_rear_2_ana_suspend { + pins = "gpio1"; + 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>; + 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"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000>; + rgltr-max-voltage = <0 1104000 2800000>; + rgltr-load-current = <0 1200000 1000000>; + cci-master = <0>; + status = "ok"; + ois_gyro,position=<3>; + ois,type=<0>; + ois_gyro,type=<2>; + }; + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8009_l5>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <3000000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_1: qcom,actuator@1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear_0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + reg = <0x0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vaf-supply = <&pm8009_l5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2","cam_vaf", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 1800000 2900000 1200000 2800000 0>; + rgltr-max-voltage = <0 1104000 1800000 2900000 1200000 3000000 0>; + rgltr-load-current = <0 1200000 1800000 800000 1200000 1000000 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>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_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 = <19200000>; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + cam_vio-supply = <&pm8009_l7>; + 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 1104000 80000 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 95 0>, + <&tlmm 144 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 = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_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 = <0>; + 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 = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 1800000 2900000 1200000 0>; + rgltr-max-voltage = <0 1104000 1800000 2900000 1200000 0>; + rgltr-load-current = <0 1200000 1800000 800000 1200000 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>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_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 = <19200000>; + }; +/*tele camera*/ + 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>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_1>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8009_l7>; + 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 1104000 80000 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 95 0>, + <&tlmm 144 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 = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + +}; + +&cam_cci1 { + actuator_rear_2: qcom,actuator@2 { + cell-index = <2>; + compatible = "qcom,actuator"; + cci-master = <1>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1200000 2800000 0>; + rgltr-max-voltage = <0 1200000 2800000 0>; + rgltr-load-current = <0 1200000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_clock_active + &cam_sensor_front_reset_active>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_front_MCLK", + "CAM_front_RESET"; + 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 = <19200000>; + }; + + eeprom_rear_2: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x03>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 3008000 0>; + rgltr-max-voltage = <0 3960000 3960000 0>; + rgltr-load-current = <0 80000 1200000 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 + &cam_sensor_rear_2_ana_active + &cam_sensor_rear_2_dvdd_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend + &cam_sensor_rear_2_dvdd_suspend>; + gpios = <&tlmm 98 0>, + <&tlmm 115 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>, + <&pm8009_gpios 2 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vdig = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VDIG_2"; + 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 = <19200000>; + }; +/*front camera*/ + 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_0>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1200000 2800000 0>; + rgltr-max-voltage = <0 1200000 2800000 0>; + rgltr-load-current = <0 1200000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_clock_active + &cam_sensor_front_reset_active>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_front_MCLK", + "CAM_front_RESET"; + 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 = <19200000>; + }; +/*ultra wide*/ + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <4>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + actuator-src = <&actuator_rear_2>; + eeprom-src = <&eeprom_rear_2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 3008000 0>; + rgltr-max-voltage = <0 3960000 3960000 0>; + rgltr-load-current = <0 80000 1200000 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 + &cam_sensor_rear_2_ana_active + &cam_sensor_rear_2_dvdd_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend + &cam_sensor_rear_2_dvdd_suspend>; + gpios = <&tlmm 98 0>, + <&tlmm 115 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>, + <&pm8009_gpios 2 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vdig = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VDIG_2"; + 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 = <19200000>; + }; +//laser start + stmvl53l1: st,stmvl53l1@0 { + compatible = "st,stmvl53l1"; + //reg = <0x29>; + laser_vdd-supply = <&pm8009_l7>; + pinctrl-names = "laser_default", "laser_suspend"; + pinctrl-0 = <&cam_sensor_laser_xsdn_active + //&cam_sensor_laser_pwren_active + &cam_sensor_laser_intr_active>; + pinctrl-1 = <&cam_sensor_laser_xsdn_suspend + //&cam_sensor_laser_pwren_suspend + &cam_sensor_laser_intr_suspend>; + xsdn-gpio = <&tlmm 76 GPIO_ACTIVE_HIGH>; + //pwren-gpio = <&tlmm 25 0>; + intr-gpio = <&tlmm 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&tlmm>; + cci-master = <1>; + status = "ok"; + }; +//laser end + +/*forth_camera*/ + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <3>; + 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_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1200000 2800000 0>; + rgltr-max-voltage = <0 1200000 2800000 0>; + rgltr-load-current = <100000 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 97 0>, + <&tlmm 116 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 = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +}; + +&tlmm { + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + 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 = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + 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 = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + 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 = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_clock_suspend: cam_sensor_rear_3_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_active: cam_sensor_front_reset_active { + /* RESET 2 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + 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 = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + 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 = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + 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 = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_intr_active: cam_sensor_laser_intr_active { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_intr_suspend: cam_sensor_laser_intr_suspend{ + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + bias-disable; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_xsdn_active: cam_sensor_laser_xsdn_active { + mux { + pins = "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio76"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_xsdn_suspend: cam_sensor_laser_xsdn_suspend{ + mux { + pins = "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio76"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_pwren_active: cam_sensor_laser_pwren_active { + /* RESET, STANDBY */ + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_pwren_suspend: cam_sensor_laser_pwren_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_t0.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_t0.dtsi new file mode 100755 index 000000000000..95516ed8e807 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlep_t0.dtsi @@ -0,0 +1,1309 @@ +&pm8009_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_2_avdd2_active: cam_sensor_rear_2_avdd2_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_avdd2_suspend: cam_sensor_rear_2_avdd2_suspend { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + bias-pull-down; + input-disable; + }; + }; + +}; + +&pm8150l_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_3_avdd_active: cam_sensor_rear_3_avdd_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_3_avdd_suspend: cam_sensor_rear_3_avdd_suspend { + pins = "gpio1"; + 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>; + 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_wide: 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"; + }; +}; + +&cam_cci0 { + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <3008000>; + rgltr-max-voltage = <3960000>; + rgltr-load-current = <300000>; + /*gpio request at sensor + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_0_vaf_suspend>; + gpios = <&tlmm 93 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_vaf";*/ + }; + + actuator_rear_2: qcom,actuator@2 { + cell-index = <2>; + 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 = <300000>; + }; + + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vaf-supply = <&pm8009_l5>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000>; + rgltr-max-voltage = <0 1104000 3000000>; + rgltr-load-current = <0 1200000 1000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_0_vaf_suspend>; + gpios = <&tlmm 93 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_vaf"; + cci-master = <0>; + ois_gyro,position=<3>; + ois_gyro,type=<2>; + ois,type=<0>; + ois,name="LC898128"; + ois_module,vendor=<1>; + ois_actuator,vednor=<1>; + ois,fw=<1>; + status = "ok"; + }; + + eeprom_rear_0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + reg = <0x0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150a_bob>; + cam_v_custom1-supply = <&pm8150_s5>; + cam_vaf-supply = <&pm8009_l5>; + 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 1104000 3008000 2040000 2800000 0>; + rgltr-max-voltage = <0 1104000 3960000 2040000 3000000 0>; + rgltr-load-current = <0 1200000 1800000 800000 1000000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 156 0>, + <&tlmm 26 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA_2"; + 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 = <19200000>; + }; + + eeprom_rear_2: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x03>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_v_custom1-supply = <&pm8150_s5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig","cam_v_custom1", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1100000 2040000 0>; + rgltr-max-voltage = <0 3960000 1100000 2040000 0>; + rgltr-load-current = <0 80000 1200000 1200000 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 + &cam_sensor_rear_2_avdd_active + &cam_sensor_rear_2_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_avdd_suspend + &cam_sensor_rear_2_avdd2_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 159 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-vana=<3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VANA"; + 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 = <19200000>; + }; + + eeprom_rear_3: qcom,eeprom@4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + reg = <0x04>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8150_s4>; + 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 1664000 3008000 0>; + rgltr-max-voltage = <0 2040000 3960000 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 + &cam_sensor_rear_3_dvdd_active + &cam_sensor_rear_3_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_3_clock_suspend + &cam_sensor_rear_3_reset_suspend + &cam_sensor_rear_3_dvdd_suspend + &cam_sensor_rear_3_avdd_suspend>; + gpios = <&tlmm 98 0>, + <&tlmm 92 0>, + <&tlmm 74 0>, + <&pm8150l_gpios 1 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-vana = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAM_RESET3", + "CAM_VDIG3", + "CAM_VANA3"; + 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 = <19200000>; + }; + +/*wide camera*/ + 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_0>; + eeprom-src = <&eeprom_rear_0>; + ois-src = <&ois_rear_0>; + led-flash-src = <&led_flash_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150a_bob>; + 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 1104000 3008000 2040000 0>; + rgltr-max-voltage = <0 1104000 3960000 2040000 0>; + rgltr-load-current = <0 1200000 1800000 800000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 156 0>, + <&tlmm 26 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA_2"; + 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 = <19200000>; + }; + +/*ultra wide*/ + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x01>; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + actuator-src = <&actuator_rear_2>; + eeprom-src = <&eeprom_rear_2>; + led-flash-src = <&led_flash_rear_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_v_custom1-supply = <&pm8150_s5>; + cam_v_custom2-supply = <&pm8150a_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig","cam_v_custom1","cam_v_custom2", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1100000 2040000 2856000 0>; + rgltr-max-voltage = <0 3960000 1100000 2040000 3104000 0>; + rgltr-load-current = <0 80000 1200000 1200000 300000 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 + &cam_sensor_rear_2_avdd_active + &cam_sensor_rear_2_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_avdd_suspend + &cam_sensor_rear_2_avdd2_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 159 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-vana=<3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VANA"; + 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 = <19200000>; + }; + +/*forth_camera*/ + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <4>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_3>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8150_s4>; + 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 1664000 3008000 0>; + rgltr-max-voltage = <0 2040000 3960000 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 + &cam_sensor_rear_3_dvdd_active + &cam_sensor_rear_3_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_3_clock_suspend + &cam_sensor_rear_3_reset_suspend + &cam_sensor_rear_3_dvdd_suspend + &cam_sensor_rear_3_avdd_suspend>; + gpios = <&tlmm 98 0>, + <&tlmm 92 0>, + <&tlmm 74 0>, + <&pm8150l_gpios 1 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-vana = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAM_RESET3", + "CAM_VDIG3", + "CAM_VANA3"; + 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 = <19200000>; + }; +}; + +&cam_cci1 { + + actuator_rear_1: qcom,actuator@1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <3008000>; + rgltr-max-voltage = <3960000>; + rgltr-load-current = <100000>; + /*gpio request at sensor + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_1_vaf_suspend>; + gpios = <&tlmm 140 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_vaf";*/ + }; + + ois_rear_1: qcom,ois@1{ + cell-index = <1>; + reg = <1>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l4>; + cam_vaf-supply = <&pm8009_l6>; + cam_v_custom1-supply = <&pm8009_l1>; + cam_v_custom2-supply = <&pm8009_l5>; + regulator-names ="cam_vio","cam_vdig","cam_vaf","cam_v_custom1","cam_v_custom2"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1056000 2800000 1104000 2800000>; + rgltr-max-voltage = <0 1056000 2800000 1104000 3000000>; + rgltr-load-current = <0 1200000 1000000 1200000 1000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_1_vaf_suspend>; + gpios = <&tlmm 140 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_vaf"; + cci-master = <0>; + ois_gyro,position=<3>; + ois_gyro,type=<2>; + ois,type=<1>; + ois,name="LC898128"; + ois_module,vendor=<1>; + ois_actuator,vednor=<2>; + ois,fw=<1>; + status = "ok"; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l4>; + cam_vana-supply = <&pm8150a_bob>; + cam_vaf-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_vaf","cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1056000 3008000 2800000 0>; + rgltr-max-voltage = <0 1056000 3960000 2800000 0>; + rgltr-load-current = <0 1104000 150000 1000000 0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_clock_active + &cam_sensor_rear_1_reset_active + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA"; + 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 = <19200000>; + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&tlmm 24 0>; + 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_AVDD"; + 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 = <19200000>; + }; + +/*tele 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>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_1>; + ois-src = <&ois_rear_1>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l4>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1104000 150000 0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_clock_active + &cam_sensor_rear_1_reset_active + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA"; + 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 = <19200000>; + }; + +/*front camera*/ + 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_0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&tlmm 24 0>; + 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_AVDD"; + 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 = <19200000>; + }; + +//laser start + stmvl53l1: st,stmvl53l1@0 { + compatible = "st,stmvl53l1"; + //reg = <0x29>; + laser_xsd-supply = <&pm8009_l7>; + laser_vdd-supply = <&pm8150a_bob>; + pinctrl-names = "laser_default", "laser_suspend"; + pinctrl-0 = <&cam_sensor_laser_xsdn_active + &cam_sensor_laser_pwren_active + &cam_sensor_laser_intr_active>; + pinctrl-1 = <&cam_sensor_laser_xsdn_suspend + &cam_sensor_laser_pwren_suspend + &cam_sensor_laser_intr_suspend>; + xsdn-gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>; + pwren-gpio = <&tlmm 25 0>; + intr-gpio = <&tlmm 138 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&tlmm>; + cci-master = <1>; + status = "ok"; + }; +//laser end +}; + +&tlmm { + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + 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 = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + 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 = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + 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 = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_clock_suspend: cam_sensor_rear_3_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + 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 = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd_active: cam_sensor_rear_0_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd_suspend: cam_sensor_rear_0_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + 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 = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + output-high; + bias-pull-up; + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd2_suspend: cam_sensor_rear_0_avdd2_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + output-low; /* active low reset */ + bias-pull-down; + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_active: cam_sensor_rear_0_vaf_active { + /* RESET, STANDBY */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_suspend: cam_sensor_rear_0_vaf_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_vaf_active: cam_sensor_rear_1_vaf_active { + /* RESET, STANDBY */ + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + output-high; + bias-pull-up; + }; + }; + + cam_sensor_rear_1_vaf_suspend: cam_sensor_rear_1_vaf_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <16>; + output-low; /* active low reset */ + bias-pull-down; + }; + }; + + cam_sensor_front_avdd_active: cam_sensor_front_avdd_active { + /* RESET 2 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + drive-strength = <16>; /* 2 MA */ + output-high; + bias-pull-up; + }; + }; + + cam_sensor_front_avdd_suspend: cam_sensor_front_avdd_suspend { + /* RESET 2 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + output-low; /* active low reset */ + bias-pull-down; + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_avdd_active: cam_sensor_rear_2_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_avdd_suspend: cam_sensor_rear_2_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_dvdd_active: cam_sensor_rear_3_dvdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio74"; + function = "gpio"; + }; + + config { + pins = "gpio74"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_dvdd_suspend: cam_sensor_rear_3_dvdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio74"; + function = "gpio"; + }; + + config { + pins = "gpio74"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_intr_active: cam_sensor_laser_intr_active { + mux { + pins = "gpio138"; + function = "gpio"; + }; + + config { + pins = "gpio138"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_intr_suspend: cam_sensor_laser_intr_suspend{ + mux { + pins = "gpio138"; + function = "gpio"; + }; + + config { + pins = "gpio138"; + bias-disable; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_xsdn_active: cam_sensor_laser_xsdn_active { + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_xsdn_suspend: cam_sensor_laser_xsdn_suspend{ + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_pwren_active: cam_sensor_laser_pwren_active { + /* RESET, STANDBY */ + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_laser_pwren_suspend: cam_sensor_laser_pwren_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev.dtsi new file mode 100755 index 000000000000..4c963434a5b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev.dtsi @@ -0,0 +1,897 @@ +&pm8009_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_2_ana_active: cam_sensor_rear_2_ana_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_ana_suspend: cam_sensor_rear_2_ana_suspend { + pins = "gpio1"; + 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>; + 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_wide: 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"; + }; +}; + +&cam_cci0 { + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8009_l5>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <3000000>; + rgltr-load-current = <600000>; + }; + + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vaf-supply = <&pm8009_l6>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000>; + rgltr-max-voltage = <0 1104000 2800000>; + rgltr-load-current = <0 1200000 1200000>; + cci-master = <0>; + status = "ok"; + ois_gyro,position=<2>; + 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 = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <0 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; +/*wide camera*/ + 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_0>; + eeprom-src = <&eeprom_rear_0>; + ois-src = <&ois_rear_0>; + led-flash-src = <&led_flash_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_vaf-supply = <&pm8009_l5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2","cam_vaf", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 2800000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 3000000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; +/*ultra_camera*/ + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x3>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_1>; + led-flash-src = <&led_flash_rear_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <100000 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; + +}; + +&cam_cci1 { + + actuator_rear_1: qcom,actuator@0 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <3008000>; + rgltr-max-voltage = <3960000>; + rgltr-load-current = <100000>; + /*gpio request at sensor + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 159 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAMIF_vaf";*/ + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_2: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x03>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2"; + 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 = <19200000>; + }; +/*front camera*/ + 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_0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +/*ultra wide*/ + 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 = <0>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_2>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active + &cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend + &cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>, + <&tlmm 159 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VAF"; + 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 = <19200000>; + }; +}; + +&tlmm { + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + 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 = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + 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 = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + 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 = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + 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 = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_avdd_suspend: cam_sensor_front_avdd_suspend { + /* RESET 2 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + 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 = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + 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 */ + }; + }; + + cam_sensor_rear_0_avdd_active: cam_sensor_rear_0_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd_suspend: cam_sensor_rear_0_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev_evt1.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev_evt1.dtsi new file mode 100755 index 000000000000..0e9fea9c08b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-oem-camera-instantnoodlev_evt1.dtsi @@ -0,0 +1,897 @@ +&pm8009_gpios{ + cam_sensor_pmi_gpio { + cam_sensor_rear_2_ana_active: cam_sensor_rear_2_ana_active { + pins = "gpio1"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_2_ana_suspend: cam_sensor_rear_2_ana_suspend { + pins = "gpio1"; + 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>; + 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_wide: 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"; + }; +}; + +&cam_cci0 { + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8009_l5>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <3000000>; + rgltr-load-current = <600000>; + }; + + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vaf-supply = <&pm8009_l6>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000>; + rgltr-max-voltage = <0 1104000 2800000>; + rgltr-load-current = <0 1200000 1200000>; + cci-master = <0>; + status = "ok"; + ois_gyro,position=<4>; + 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 = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <0 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; +/*wide camera*/ + 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_0>; + eeprom-src = <&eeprom_rear_0>; + ois-src = <&ois_rear_0>; + led-flash-src = <&led_flash_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l1>; + cam_vana-supply = <&pm8150_s5>; + cam_v_custom1-supply = <&pm8150a_bob>; + cam_v_custom2-supply = <&pm8009_l2>; + cam_vaf-supply = <&pm8009_l5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_v_custom2","cam_vaf", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2040000 3008000 1100000 2800000 0>; + rgltr-max-voltage = <0 1104000 2040000 3960000 1100000 3000000 0>; + rgltr-load-current = <0 1200000 300000 250000 600000 600000 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 + &cam_sensor_rear_0_avdd2_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend + &cam_sensor_rear_0_avdd2_suspend>; + gpios = <&tlmm 94 0>, + <&tlmm 145 0>, + <&tlmm 26 0>, + <&tlmm 156 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_MCLK0", + "CAM_RESET0", + "CAM_VANA", + "CAM_VANA2"; + 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 = <19200000>; + }; +/*ultra_camera*/ + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x3>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_1>; + led-flash-src = <&led_flash_rear_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 0>; + rgltr-max-voltage = <0 3960000 0>; + rgltr-load-current = <100000 800000 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 + &cam_sensor_rear_1_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend + &cam_sensor_rear_1_avdd_suspend>; + gpios = <&tlmm 95 0>, + <&tlmm 144 0>, + <&tlmm 139 0>; + 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_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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 = <19200000>; + }; + +}; + +&cam_cci1 { + + actuator_rear_1: qcom,actuator@0 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <3008000>; + rgltr-max-voltage = <3960000>; + rgltr-load-current = <100000>; + /*gpio request at sensor + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 159 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAMIF_vaf";*/ + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_2: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x03>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2"; + 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 = <19200000>; + }; +/*front camera*/ + 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_0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&pm8009_l3>; + 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 1056000 3008000 0>; + rgltr-max-voltage = <0 1056000 3960000 0>; + rgltr-load-current = <0 1200000 250000 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>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend>; + gpios = <&tlmm 96 0>, + <&tlmm 90 0>, + <&tlmm 24 0>; + 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 = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +/*ultra wide*/ + 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 = <0>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_2>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3008000 1056000 0>; + rgltr-max-voltage = <0 3960000 1056000 0>; + rgltr-load-current = <0 250000 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 + &cam_sensor_rear_2_ana_active + &cam_sensor_rear_2_vaf_active>; + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend + &cam_sensor_rear_2_ana_suspend + &cam_sensor_rear_2_vaf_suspend>; + gpios = <&tlmm 97 0>, + <&tlmm 78 0>, + <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>, + <&tlmm 159 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 = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA_2", + "CAM_VAF"; + 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 = <19200000>; + }; +}; + +&tlmm { + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + 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 = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + 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 = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + 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 = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + 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 = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + 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 = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_avdd_suspend: cam_sensor_front_avdd_suspend { + /* RESET 2 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + 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 = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + 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 */ + }; + }; + + cam_sensor_rear_0_avdd_active: cam_sensor_rear_0_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd_suspend: cam_sensor_rear_0_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; 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 100755 index 000000000000..6c7655b20cd8 --- /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 100755 index 000000000000..beff5884daf8 --- /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 100755 index 000000000000..07d398e9e16c --- /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 100755 index 000000000000..9dc1a26207f3 --- /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 100755 index 000000000000..6de6c6c4c859 --- /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 100755 index 000000000000..8a05258d0e43 --- /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 100755 index 000000000000..2d888cbce876 --- /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 100755 index 000000000000..cddf9165ff1f --- /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 100755 index 000000000000..aff695014114 --- /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 100755 index 000000000000..ffefa6a671d6 --- /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 100755 index 000000000000..fe84525de197 --- /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 100755 index 000000000000..d066925a86f2 --- /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 100755 index 000000000000..11eb3a30d232 --- /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 100755 index 000000000000..8ffa0eb7749d --- /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 100755 index 000000000000..89df5ffd4029 --- /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 100755 index 000000000000..feb55406288c --- /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 100755 index 000000000000..c909864db377 --- /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 100755 index 000000000000..37330078b1ff --- /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 100755 index 000000000000..06a95cadbd58 --- /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 100755 index 000000000000..f62ce3b9d7b5 --- /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 100755 index 000000000000..310ce40cd902 --- /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 100755 index 000000000000..ef40a2e7b3e6 --- /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 100755 index 000000000000..5f4be88fb88f --- /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 100755 index 000000000000..87b4a76a3a96 --- /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 100755 index 000000000000..3bee9f6f104d --- /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 100755 index 000000000000..e9d31359ed5b --- /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 100755 index 000000000000..5a2ac01716d3 --- /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 100755 index 000000000000..6195f8c82a53 --- /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 100755 index 000000000000..032fc39b91bf --- /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 100755 index 000000000000..37c0dfcd7d75 --- /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 100755 index 000000000000..476c34c01d34 --- /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 100755 index 000000000000..e9b7bac34504 --- /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 100755 index 000000000000..a7d85dfd9194 --- /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 100755 index 000000000000..fadbce641428 --- /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 100755 index 000000000000..b81aad8801d0 --- /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 100755 index 000000000000..1f6e32ac60f8 --- /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 100755 index 000000000000..3eb83e40a9c0 --- /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 100755 index 000000000000..6257b55c4e1d --- /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 100755 index 000000000000..e6bda66f50ac --- /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 100755 index 000000000000..d6a849eb4925 --- /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 000000000000..07d398e9e16c --- /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 000000000000..8e9a04ae0a3f --- /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 000000000000..9dc1a26207f3 --- /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 000000000000..6de6c6c4c859 --- /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-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 000000000000..8a05258d0e43 --- /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 000000000000..2d888cbce876 --- /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 000000000000..8b3aedf2c52d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,218 @@ +&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,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/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 000000000000..090c75f8b90d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -0,0 +1,205 @@ +&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,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/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 000000000000..698c466b2ffd --- /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 000000000000..78ae48b0ff86 --- /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 000000000000..eb25ee85172f --- /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 = <80>; + 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 = <2>; + 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 FF 00 02 11 00 + 05 01 00 00 FF 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-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 000000000000..d066925a86f2 --- /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-nt37800-amoled-dsc-fhd-plus-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt37800-amoled-dsc-fhd-plus-cmd.dtsi new file mode 100644 index 000000000000..79f7dafee036 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt37800-amoled-dsc-fhd-plus-cmd.dtsi @@ -0,0 +1,335 @@ +/* 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_boe_nt37800_fhd_dsc_cmd: qcom,mdss_dsi_boe_nt37800_fhd_dsc_cmd{ + qcom,mdss-dsi-panel-name = "BOE dsc cmd mode oneplus dsi panel"; + qcom,mdss-dsi-panel-manufacture = "BOE"; + qcom,mdss-dsi-panel-version = "DSC"; + qcom,mdss-dsi-backlight-version = "BOE"; + qcom,mdss-dsi-backlight-manufacture = "BOE"; + 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 = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-te-check-enable; + 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-dsi-panel-jitter = <0x4 0x1>; + 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-peak-brightness = <5400000>; + qcom,mdss-dsi-panel-average-brightness = <2000000>; + qcom,mdss-dsi-panel-blackness-level = <2000>; + qcom,mdss-dsi-panel-seria-num-year-index = <12>; + qcom,mdss-dsi-panel-seria-num-mon-index = <12>; + qcom,mdss-dsi-panel-seria-num-day-index = <13>; + qcom,mdss-dsi-panel-seria-num-hour-index = <14>; + qcom,mdss-dsi-panel-seria-num-min-index = <15>; + qcom,mdss-dsi-panel-seria-num-sec-index = <16>; +// 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 = <0x9F>; + 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,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-resolution-switch-immediate"; + qcom,mdss-dsi-panel-clockrate = <830000000>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + 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-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-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + qcom,mdss-dsi-panel-status-read-length = <1>; + 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-timing-switch-command = [ + 39 01 00 00 00 00 06 F0 55 AA 52 08 00 /* 60 FPS */ + 15 01 00 00 00 00 02 6F 0E + 15 01 00 00 00 00 02 BA 18 + 15 01 00 00 00 00 02 6F 03 + 39 01 00 00 00 00 04 C0 80 00 00 + 39 01 00 00 00 00 02 26 01 /* 60 FPS */ + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 06 F0 55 AA 52 08 00 + 15 01 00 00 00 00 02 6F 0E + 15 01 00 00 00 00 02 BA 18 + 15 01 00 00 00 00 02 6F 03 + 39 01 00 00 00 00 04 C0 80 00 00 + 39 01 00 00 00 00 02 26 01 + 15 01 00 00 00 00 01 35 + 39 01 00 00 00 00 05 3B 00 08 00 08 + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 05 51 0F FF 0F FF + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 5F + 39 01 00 00 00 00 13 93 89 28 00 14 02 00 02 0e 01 e8 00 07 05 0e 05 16 10 f0 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 11 + 05 01 00 00 00 00 01 2c + 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 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 51 0F FF + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 51 06 40 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 51 0F FF + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 51 06 40 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_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,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <20>; + 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-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-mdp-transfer-time-us = <8000>; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-clockrate = <830000000>; + 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-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + qcom,mdss-dsi-panel-status-read-length = <1>; + 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-timing-switch-command = [ + 39 01 00 00 00 00 06 F0 55 AA 52 08 00 + 15 01 00 00 00 00 02 6F 03 + 39 01 00 00 00 00 04 C0 00 00 00 + 15 01 00 00 00 00 02 26 02 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 06 F0 55 AA 52 08 00 + 15 01 00 00 00 00 02 6F 03 + 39 01 00 00 00 00 04 C0 00 00 00 + 15 01 00 00 00 00 02 26 02 + 15 01 00 00 00 00 01 35 + 39 01 00 00 00 00 05 3B 00 08 00 08 + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 05 51 0F FF 0F FF + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 5F + 39 01 00 00 00 00 13 93 89 28 00 14 02 00 02 0e 01 e8 00 07 05 0e 05 16 10 f0 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 11 + 05 01 00 00 00 00 01 2c + 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 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 51 0F FF + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 51 06 40 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 51 0F FF + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 51 06 40 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_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,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <20>; + 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_boe_nt37800_fhd_dsc_cmd { + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + 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,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,avdd-gpio = <&tlmm 24 0>; +}; + +&soc { + dsi_boe_nt37800_fhd_dsc_cmd_display { + qcom,dsi-display-active; + }; +}; + +&dsi_boe_nt37800_fhd_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 { /* fhd 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>; + qcom,panel-roi-alignment=<540 20 540 20 540 20>; + }; + 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>; + qcom,panel-roi-alignment=<540 20 540 20 540 20>; + }; + }; +}; + + + 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 000000000000..fa21c0c3ac11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-cmd.dtsi @@ -0,0 +1,324 @@ +&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 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-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 + 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 + 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; + }; + + 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 + 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 + 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-120hz-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-video.dtsi new file mode 100644 index 000000000000..b312662069b2 --- /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-60hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-cmd.dtsi new file mode 100644 index 000000000000..1303acb4a2c3 --- /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 000000000000..cfda350675ad --- /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 000000000000..3b1a851a055a --- /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 000000000000..dd76a024b17b --- /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-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 000000000000..3137cb65e3e4 --- /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 000000000000..5cd896fcd213 --- /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 000000000000..11eb3a30d232 --- /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_amb655x_fhd_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_amb655x_fhd_dsc.dtsi new file mode 100644 index 000000000000..f1d9d960d0e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_amb655x_fhd_dsc.dtsi @@ -0,0 +1,808 @@ +/* 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_amb655x_dsc_cmd: qcom,mdss_dsi_samsung_amb655x_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung amb655x fhd cmd mode dsc dsi panel"; + 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 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <151>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + /* 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,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-lp11-init; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + 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-seria-num-year-index = <12>; + qcom,mdss-dsi-panel-seria-num-mon-index = <12>; + qcom,mdss-dsi-panel-seria-num-day-index = <13>; + qcom,mdss-dsi-panel-seria-num-hour-index = <14>; + qcom,mdss-dsi-panel-seria-num-min-index = <15>; + qcom,mdss-dsi-panel-seria-num-sec-index = <16>; + qcom,mdss-dsi-panel-seria-num-msec-high-index = <17>; + qcom,mdss-dsi-panel-seria-num-msec-low-index = <18>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-mdp-transfer-time-us = <12000>; //for 60fps + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + 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-h-sync-pulse = <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-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 0C 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 81 9E + 11 00 00 89 30 80 09 60 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 02 9D 01 + 39 01 00 00 00 00 03 F0 A5 A5 + + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + + /* VLIN CURRENT LIMIT */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 D5 24 9E 9E 00 20 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OSC Select */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 16 + 39 01 00 00 00 00 02 D1 22 + 39 01 00 00 00 00 02 D6 11 + 39 01 00 00 00 00 03 FC A5 A5 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 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 + /* FD Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 D5 8D + 39 01 00 00 00 00 02 B0 0A + 39 01 00 00 00 00 02 D5 05 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FFC Function */ + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 E4 A6 75 A3 + 39 01 00 00 00 00 0F E9 11 75 A6 75 A3 4B 17 AC 4B 17 AC 00 19 19 + 39 01 00 00 3D 00 03 FC 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 02 B0 01 + 39 01 00 00 00 00 02 B7 4C + 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 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 15 00 01 28 + 05 01 00 00 65 00 01 10 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + 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 = [ + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 1E 00 03 51 0A 18 + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 1E 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-hbm-off-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 02 B7 4C + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + 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 */ + 05 01 00 00 11 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 00 + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 00 00 + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 E3 00 + 39 01 00 00 11 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + /* 60hz Transition */ + 05 01 00 00 11 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 11 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + /* 60hz Transition */ + 05 01 00 00 11 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 11 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + /* 60hz Transition */ + 05 01 00 00 11 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 11 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 1E 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + /* 60hz Transition */ + 05 01 00 00 11 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 11 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 1E 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-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 02 B7 4C + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + + 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 02 C2 07 + 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 02 C2 27 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dimming-setting-mode-1-command = [ + 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 06 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 93 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 28 + ]; + qcom,mdss-dsi-dimming-setting-mode-0-command = [ + 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 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 02 81 90 + 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 A8 0D 04 35 D2 12 0B 00 B3 46 EA D2 C7 0E C3 E5 EC 17 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-command = [ + 39 01 00 00 00 00 02 81 90 + 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 A8 0D 04 35 D2 12 0B 00 B3 46 EA D2 C7 0E C3 E5 EC 17 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-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + 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-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dimming-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dimming-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-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 30 540 30 540 30>; + qcom,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <30>; + 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-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + 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-h-sync-pulse = <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-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 = [ + /* 120hz 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 = [ + /* DSC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 81 9E + 11 00 00 89 30 80 09 60 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 02 9D 01 + 39 01 00 00 00 00 03 F0 A5 A5 + + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + + /* VLIN CURRENT LIMIT */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 D5 24 9E 9E 00 20 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OSC Select */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 16 + 39 01 00 00 00 00 02 D1 22 + 39 01 00 00 00 00 02 D6 11 + 39 01 00 00 00 00 03 FC A5 A5 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 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 + /* FD Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 D5 8D + 39 01 00 00 00 00 02 B0 0A + 39 01 00 00 00 00 02 D5 05 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FFC Function */ + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 E4 A6 75 A3 + 39 01 00 00 00 00 0F E9 11 75 A6 75 A3 4B 17 AC 4B 17 AC 00 19 19 + 39 01 00 00 3D 00 03 FC 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 02 B0 01 + 39 01 00 00 00 00 02 B7 4C + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /* 120hz 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 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 15 00 01 28 + 05 01 00 00 65 00 01 10 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + 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 = [ + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 0F 00 03 51 0A 18 + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 0F 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-hbm-off-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 02 B7 4C + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + 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 */ + 05 01 00 00 09 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 00 + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 00 00 + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 E3 00 + 39 01 00 00 09 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + /* 120hz Transition */ + 05 01 00 00 09 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 09 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + /* 120hz Transition */ + 05 01 00 00 09 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 09 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + /* 120hz Transition */ + 05 01 00 00 09 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 09 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 0F 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + /* 120hz Transition */ + 05 01 00 00 09 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0B + 39 01 00 00 00 00 03 D8 09 70 + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 09 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + + 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 02 B7 44 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + 39 01 00 00 0F 00 03 51 0C A8 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-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 02 B7 4C + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 39 01 00 00 00 00 02 53 20 + ]; + + 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 02 C2 07 + 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 02 C2 27 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dimming-setting-mode-1-command = [ + 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 06 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 93 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 28 + ]; + qcom,mdss-dsi-dimming-setting-mode-0-command = [ + 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 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 02 81 90 + 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 A8 0D 04 35 D2 12 0B 00 B3 46 EA D2 C7 0E C3 E5 EC 17 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-command = [ + 39 01 00 00 00 00 02 81 90 + 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 A8 0D 04 35 D2 12 0B 00 B3 46 EA D2 C7 0E C3 E5 EC 17 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-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + 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-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dimming-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dimming-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-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 30 540 30 540 30>; + qcom,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <30>; + 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_amb655x_dsc_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 = <2047>; + qcom,mdss-brightness-default-val = <360>; + qcom,mdss-brightness-max-level = <2047>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,vddd-gpio = <&tlmm 24 0>; +}; + +&soc { + dsi_samsung_amb655x_dsc_cmd { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_amb655x_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","pw_bb_clk2"; + qcom,mdss-dsi-display-timings { + timing@0 { /* fhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + timing@1 { /* fhd 120hz */ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + 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_ana6705_fhd_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ana6705_fhd_dsc.dtsi new file mode 100644 index 000000000000..0c972454c92c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ana6705_fhd_dsc.dtsi @@ -0,0 +1,807 @@ +/* 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_ana6705_dsc_cmd: qcom,mdss_dsi_samsung_ana6705_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung ana6705 fhd cmd mode dsc dsi panel"; + 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 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <151>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + /* 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,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-lp11-init; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + 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-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-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 = <830000000>; + 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-h-sync-pulse = <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-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 */ + 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 + /* T2M CLK Change 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 01 + 39 01 00 00 00 00 02 F5 77 + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 05 F5 10 40 10 40 + 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 + /* 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 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 03 F0 A5 A5 + /* Low luminance flicker */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 08 + 39 01 00 00 00 00 02 F2 A0 + 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 + /* T2M CLK fix Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 87 + 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 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 + /* OPEC */ + 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-brightness-on-command = [ + /* HBM Mode ON */ + 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-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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 20 00 03 51 0E EC /* 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 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 20 00 03 51 0E EC /* 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 0E EC /* 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 + ]; + 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-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-command = [ + ]; + + qcom,mdss-dsi-panel-read-register-ed-command = [ + 39 01 00 00 00 00 02 ED 97 + ]; + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-ed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + 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 = <830000000>; + 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-h-sync-pulse = <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-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 */ + 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 00 + 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 + /* T2M CLK Change 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 01 + 39 01 00 00 00 00 02 F5 77 + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 05 F5 10 40 10 40 + 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 + /* 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 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 03 F0 A5 A5 + /* Low luminance flicker */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 08 + 39 01 00 00 00 00 02 F2 A0 + 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 + /* T2M CLK fix Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 87 + 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 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 + /* 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-brightness-on-command = [ + /* HBM Mode ON */ + 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-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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 16 00 03 51 0E EC /* 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 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 16 00 03 51 0E EC /* 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 0E EC /* 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 + ]; + 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-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-command = [ + ]; + + qcom,mdss-dsi-panel-read-register-ed-command = [ + 39 01 00 00 00 00 02 ED 97 + ]; + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-ed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + 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_ana6705_dsc_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 = <2047>; + qcom,mdss-brightness-default-val = <360>; + qcom,mdss-brightness-max-level = <2047>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,vddd-gpio = <&tlmm 24 0>; +}; + +&soc { + dsi_samsung_ana6705_dsc_cmd { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_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","pw_bb_clk2"; + qcom,mdss-dsi-display-timings { + timing@0 { /* fhd 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_ana6706_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ana6706_dsc.dtsi new file mode 100644 index 000000000000..2455c1fa459d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ana6706_dsc.dtsi @@ -0,0 +1,1850 @@ +/* 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_ana6706_dsc_cmd: qcom,mdss_dsi_samsung_ana6706_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung ana6706 dsc cmd mode panel"; + 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 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <154>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-resolution-switch-immediate"; + /* 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,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 = <0x9F>; + qcom,mdss-dsi-panel-status-read-length = <1>; + + qcom,mdss-dsi-lp11-init; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + 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-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-display-timings { + timing@0 { + qcom,mdss-mdp-transfer-time-us = <6130>; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2376>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <48>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <1100>; + qcom,mdss-dsi-v-front-porch = <1100>; + qcom,mdss-dsi-v-pulse-width = <188>; + 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 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 02 /* 60HZ */ + 15 01 00 00 00 00 02 BA 02 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + 39 01 00 00 06 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 02 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 48 + 04 38 00 48 02 1C 02 1C + 02 00 02 52 00 20 06 3B + 00 07 00 0F 01 B1 01 6A + 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 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 02 /* 60HZ */ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* Aod Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 F4 8A + 15 01 00 00 00 00 02 BB 29 + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 02 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 02 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 02 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 02 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <72>; + 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-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2376>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <48>; + qcom,mdss-dsi-h-pulse-width = <8>; + 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 = <2>; + 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 = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 22 /* 120HZ */ + 15 01 00 00 00 00 02 BA 02 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* for scanline */ + 15 01 00 00 00 00 02 B9 01 + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 05 B9 0C 54 00 0B + 39 01 00 00 07 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 02 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 48 + 04 38 00 48 02 1C 02 1C + 02 00 02 52 00 20 06 3B + 00 07 00 0F 01 B1 01 6A + 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 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 22 /* 120HZ */ + 15 01 00 00 00 00 02 F7 0F + /* for scanline */ + 15 01 00 00 00 00 02 B9 01 + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 05 B9 0C 54 00 0B + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* Aod Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 F4 8A + 15 01 00 00 00 00 02 BB 29 + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 22 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 22 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 22 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 22 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <72>; + 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@2 { + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-clockrate = <1452000000>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3168>; + qcom,mdss-dsi-h-front-porch = <88>; + qcom,mdss-dsi-h-back-porch = <56>; + qcom,mdss-dsi-h-pulse-width = <8>; + 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 = <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-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 20 /* 120HZ */ + 15 01 00 00 00 00 02 BA 03 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + 39 01 00 00 07 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 03 + 39 01 00 00 00 00 59 9E + 12 00 00 AB 30 80 0C 60 + 05 A0 00 60 02 D0 02 D0 + 02 00 02 C2 00 20 09 62 + 00 0A 00 0F 01 44 00 CC + 18 00 10 F0 07 10 20 00 + 06 0F 0F 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 02 02 22 00 2A 40 + 2A BE 3A FC 3A FA 3A F8 + 3B 38 3B 78 3B B6 4B B6 + 4B F4 4B F4 6C 34 84 74 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 20 /* 120HZ */ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* Aod Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 F4 8A + 15 01 00 00 00 00 02 BB 29 + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 20 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 20 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 20 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 20 /*120HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <720 720>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <96>; + 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@3 { + qcom,mdss-mdp-transfer-time-us = <12000>; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3168>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <80>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <180>; + qcom,mdss-dsi-v-front-porch = <180>; + qcom,mdss-dsi-v-pulse-width = <12>; + 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 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 00 /* 60HZ */ + 15 01 00 00 00 00 02 BA 03 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + 39 01 00 00 08 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 03 + 39 01 00 00 00 00 59 9E + 11 00 00 AB 30 A0 0C 60 + 05 A0 00 10 02 D0 03 84 + 01 9A 02 68 00 19 01 D1 + 00 0E 00 09 04 CD 05 D6 + 16 00 10 EC 07 10 20 00 + 06 0F 0F 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 02 02 22 00 2A 40 + 32 BE 3A FC 3A FA 3A F8 + 3B 38 3B 78 3B 76 4B B6 + 4B B4 4B F4 5B F4 7C 34 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 00 /*60HZ*/ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* Aod Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 F4 8A + 15 01 00 00 00 00 02 BB 29 + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 00 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 00 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 00 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 60 00 /*60HZ*/ + 15 00 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Normal Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 6A 00 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <720 720>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + 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; + }; + }; + }; +}; + +&dsi_samsung_ana6706_dsc_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 = <2047>; + qcom,mdss-brightness-default-val = <360>; + qcom,mdss-brightness-max-level = <2047>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,vddr-gpio = <&tlmm 8 0>; + qcom,vddd-gpio = <&tlmm 24 0>; +}; + +&soc { + dsi_samsung_ana6706_dsc_cmd { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_ana6706_dsc_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0","pw_bb_clk2"; + qcom,mdss-dsi-display-timings { + timing@0 { /* FHD+ 60hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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+ 120hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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@2 { /* WQHD+ 120hz 726Mhz 1452Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 2F 0C 0C 2A 27 0C 0D 09 02 04 00 26 1B]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + timing@3 { /* WQHD+ 60hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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_dd305_fhd_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_dd305_fhd_dsc.dtsi new file mode 100644 index 000000000000..7f898588561b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_dd305_fhd_dsc.dtsi @@ -0,0 +1,835 @@ +/* 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_dd305_dsc_cmd: qcom,mdss_dsi_samsung_dd305_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung dd305 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 1>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-brightness-default-val = <180>; + 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,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 = <830000000>; + 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 */ + 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 + /* T2M CLK Change 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 01 + 39 01 00 00 00 00 02 F5 77 + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 05 F5 10 40 10 40 + 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 + /* 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 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 03 F0 A5 A5 + /* Low luminance flicker */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 08 + 39 01 00 00 00 00 02 F2 A0 + 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 + /* T2M CLK fix Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 87 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SP fix setting */ + 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 04 BE 80 80 B0 + 39 01 00 00 00 00 02 B0 8A + 39 01 00 00 00 00 13 BF 01 + 70 01 70 01 30 01 10 00 FF + 00 B5 00 B5 00 80 00 80 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SP */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 D5 + 39 01 00 00 00 00 02 C2 01 + 39 01 00 00 00 00 02 B0 D4 + 39 01 00 00 00 00 02 C2 38 + 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 B7 01 13 /* 0x13 : 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 + /* OPEC */ + 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 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 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 1B /* 0x1B : DLY OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 09 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 = [ + /* HBM Mode ON */ + 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 1B /* 0x1B : 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 03 FF + /* 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-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 02 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 02 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 09 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-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_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-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 = <830000000>; + 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 + /* OPEC */ + 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 00 + 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 + /* T2M CLK Change 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 01 + 39 01 00 00 00 00 02 F5 77 + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 05 F5 10 40 10 40 + 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 + /* 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 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 03 F0 A5 A5 + /* Low luminance flicker */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 08 + 39 01 00 00 00 00 02 F2 A0 + 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 + /* T2M CLK fix Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 87 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SP fix setting */ + 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 04 BE 80 80 B0 + 39 01 00 00 00 00 02 B0 8A + 39 01 00 00 00 00 13 BF 01 + 70 01 70 01 30 01 10 00 FF + 00 B5 00 B5 00 80 00 80 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SP */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 D5 + 39 01 00 00 00 00 02 C2 01 + 39 01 00 00 00 00 02 B0 D4 + 39 01 00 00 00 00 02 C2 38 + 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 B7 01 13 /* 0x13 : 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 + /* 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 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 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 1B /* 0x1B : DLY OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 09 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 05 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 = [ + /* HBM Mode ON */ + 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 1B /* 0x1B : 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 03 FF + /* 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-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 02 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 02 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 09 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 07 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-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_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-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; + }; + }; + }; +}; + +&dsi_samsung_dd305_dsc_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,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,avdd-gpio = <&tlmm 24 0>; +}; + +&soc { + dsi_samsung_dd305_dsc_cmd { + qcom,dsi-display-active; + }; +}; +&dsi_samsung_dd305_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","pw_bb_clk2"; + 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_oneplus_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_oneplus_dsc.dtsi new file mode 100644 index 000000000000..082772e2e84f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_oneplus_dsc.dtsi @@ -0,0 +1,2671 @@ +/* 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_oneplus_dsc_cmd: qcom,mdss_dsi_samsung_oneplus_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung dsc cmd mode oneplus 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-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 8>, <0 1>, <1 5>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + 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-lane-map = "lane_map_0123"; + 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-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 = <71>; + qcom,mdss-pan-physical-height-dimension = <154>; + qcom,mdss-dsi-init-delay-us = <1000>; + //qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-high-brightness-panel; + qcom,mdss-dsi-acl-cmd-index = <0>; + qcom,mdss-dsi-acl-mode-index = <1>; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-resolution-switch-immediate"; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + /* 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,mdss-dsi-panel-seria-num-year-index = <12>; + qcom,mdss-dsi-panel-seria-num-mon-index = <12>; + qcom,mdss-dsi-panel-seria-num-day-index = <13>; + qcom,mdss-dsi-panel-seria-num-hour-index = <14>; + qcom,mdss-dsi-panel-seria-num-min-index = <15>; + qcom,mdss-dsi-panel-seria-num-sec-index = <16>; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + + /* + * ************************************************************************************************************************ + * DMS (Dynamic Mode Switch) + * ************************************************************************************************************************ + */ + 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 = <1042000000>; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3120>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <1156>; + qcom,mdss-dsi-v-front-porch = <400>; + qcom,mdss-dsi-v-pulse-width = <28>; + 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-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + //29 01 00 00 00 00 03 9F A5 A5 + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 29 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 09 10 B4 24 FB /* FFC Setting; 0x09 : Enable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-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-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 11 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 11 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 14 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 0D 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 11 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + 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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 05 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 39 01 00 0A 00 00 16 67 BB 0E 04 3E D8 12 09 05 EA 41 E2 D0 E5 09 F6 D0 D0 11 F8 FE DC + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 D3 03 00 11 E4 01 0B 06 F0 1A FA FC E5 09 F6 EA F3 01 FC FF EA + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <720 720>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <65>; + 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; + }; + + 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-panel-framerate = <90>; + qcom,mdss-dsi-panel-clockrate = <1042000000>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <8>; + qcom,mdss-dsi-v-front-porch = <4>; + 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-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A /* Level2 key Access Enable */ + //29 01 00 00 00 00 03 9F A5 A5 /* Level1 key Access Enable */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 29 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 29 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 09 10 B4 24 FB /* FFC Setting; 0x09 : Enable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame */ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 29 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 29 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame */ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 0C 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 0C 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 10 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 29 01 00 00 0C 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 00 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 39 01 00 0A 00 00 16 67 BB 0E 04 3E D8 12 09 05 EA 41 E2 D0 E5 09 F6 D0 D0 11 F8 FE DC + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 D3 03 00 11 E4 01 0B 06 F0 1A FA FC E5 09 F6 EA F3 01 FC FF EA + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 60 540 60 540 60>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <60>; + 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@2{ + 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 = <1042000000>; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <1156>; + qcom,mdss-dsi-v-front-porch = <400>; + qcom,mdss-dsi-v-pulse-width = <28>; + 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-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A /* Level2 key Access Enable */ + //29 01 00 00 00 00 03 9F A5 A5 /* Level1 key Access Enable */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 29 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 29 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 09 10 B4 24 FB /* FFC Setting; 0x09 : Enable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame */ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 29 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 01 /* Scaler enable(x1.78) */ + 39 01 00 00 00 00 59 0A /* PPS Setting (1080 x 2340) */ + 11 00 00 89 30 80 09 24 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + 29 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 29 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 09 23 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame */ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-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-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 11 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 11 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 14 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 0D 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 11 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + 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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 05 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 39 01 00 0A 00 00 16 67 BB 0E 04 3E D8 12 09 05 EA 41 E2 D0 E5 09 F6 D0 D0 11 F8 FE DC + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 D3 03 00 11 E4 01 0B 06 F0 1A FA FC E5 09 F6 EA F3 01 FC FF EA + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 60 540 60 540 60>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <60>; + 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@3{ + 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-panel-framerate = <90>; + qcom,mdss-dsi-panel-clockrate = <1042000000>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3120>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <8>; + qcom,mdss-dsi-v-front-porch = <4>; + 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-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + //29 01 00 00 00 00 03 9F A5 A5 + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 29 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 09 10 B4 24 FB /* FFC Setting; 0x09 : Enable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 0C 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 0C 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 10 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 29 01 00 00 0C 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 00 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 00 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 39 01 00 0A 00 00 16 67 BB 0E 04 3E D8 12 09 05 EA 41 E2 D0 E5 09 F6 D0 D0 11 F8 FE DC + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 10 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 D3 03 00 11 E4 01 0B 06 F0 1A FA FC E5 09 F6 EA F3 01 FC FF EA + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <720 720>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <65>; + 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; + }; + + }; + }; +}; + +&dsi_samsung_oneplus_dsc_cmd { + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + 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,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + /* #if defined(CONFIG_PXLW_IRIS5) */ + qcom,platform-iris-reset-gpio = <&tlmm 174 0>; + qcom,platform-analog-bypass-gpio = <&tlmm 173 0>; + qcom,platform-analog-bypass-status-gpio = <&tlmm 112 0>; + //qcom,platform-iris-vdd-gpio = <&tlmm 175 0>; + /* #endif */ +}; + +&soc { + dsi_samsung_oneplus_dsc_cmd_display { + qcom,dsi-display-active; + }; +}; +&dsi_samsung_oneplus_dsc_cmd { + //qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0","pw_bb_clk2"; + qcom,mdss-dsi-display-timings { + timing@0 { /* wqhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + }; + timing@1 { /* fhd 90hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<540 60 540 60 540 60>; + }; + timing@2 { /* fhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<540 60 540 60 540 60>; + }; + timing@3 { /* wqhd 90hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + }; + }; +}; + + diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_oneplus_dsc_2nd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_oneplus_dsc_2nd.dtsi new file mode 100644 index 000000000000..b3fd88d12c3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_oneplus_dsc_2nd.dtsi @@ -0,0 +1,1376 @@ +/* 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_oneplus_dsc_cmd_2nd: qcom,mdss_dsi_samsung_oneplus_dsc_cmd_2nd { + qcom,mdss-dsi-panel-name = "samsung dsc cmd mode oneplus dsi panel 2nd"; + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + + 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-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 2>, <1 5>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + 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-lane-map = "lane_map_0123"; + 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-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 = <71>; + qcom,mdss-pan-physical-height-dimension = <154>; + qcom,mdss-dsi-init-delay-us = <1000>; +// qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-high-brightness-panel; + qcom,mdss-dsi-acl-cmd-index = <0>; + qcom,mdss-dsi-acl-mode-index = <1>; + qcom,mdss-bl-high2bit; + qcom,mdss-dsi-panel-jitter = <0x8 0xa>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-resolution-switch-immediate"; + + /* 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,mdss-dsi-panel-seria-num-year-index = <12>; + qcom,mdss-dsi-panel-seria-num-mon-index = <12>; + qcom,mdss-dsi-panel-seria-num-day-index = <13>; + qcom,mdss-dsi-panel-seria-num-hour-index = <14>; + qcom,mdss-dsi-panel-seria-num-min-index = <15>; + qcom,mdss-dsi-panel-seria-num-sec-index = <16>; +// 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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + + /* + * ************************************************************************************************************************ + * DMS (Dynamic Mode Switch) + * ************************************************************************************************************************ + */ + 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 = <1042000000>; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3120>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <1156>; + qcom,mdss-dsi-v-front-porch = <400>; + qcom,mdss-dsi-v-pulse-width = <28>; + 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 = <0x8 0xa>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + //29 01 00 00 00 00 03 9F A5 A5 + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 29 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 78 00 01 29 + /*disable loading effect*/ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-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-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 11 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 11 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 14 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 0D 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 11 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + 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-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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 05 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E5 08 00 86 FF 00 04 03 F8 1B F0 E8 E9 03 ED DD F0 00 FF FE E4 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-laoding-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-laoding-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 EA 12 06 4A F4 14 09 02 BF 47 FC DC D3 0B E5 D2 F6 14 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-laoding-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-laoding-effect-disable-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <720 720>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <65>; + 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; + }; + + timing@1{ + 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 = <1042000000>; + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3120>; + qcom,mdss-dsi-h-front-porch = <16>; + 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 = <1156>; + qcom,mdss-dsi-v-front-porch = <400>; + qcom,mdss-dsi-v-pulse-width = <28>; + 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 = <0x8 0xa>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + //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 = <0x9F>; + 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-id2-command = [06 01 00 00 00 00 02 0E 00]; + qcom,mdss-dsi-panel-id3-command = [06 01 00 00 00 00 02 0F 00]; + qcom,mdss-dsi-panel-id4-command = [06 01 00 00 00 00 02 C4 00]; + qcom,mdss-dsi-panel-id5-command = [06 01 00 00 00 00 02 E7 00]; + qcom,mdss-dsi-panel-id6-command = [06 01 00 00 00 00 02 EA 00]; + qcom,mdss-dsi-panel-id7-command = [06 01 00 00 00 00 02 FB 00]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-esd-registed-longread-command = [ + 37 01 00 00 05 00 02 22 00 + ]; + 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-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-esd-registed-longread-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + //29 01 00 00 00 00 03 9F A5 A5 + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 29 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 29 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + //29 01 00 00 00 00 03 9F 5A 5A + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-t-clk-post = <0x19>; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 78 00 01 29 + /*disable loading effect*/ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-113mhz-osc-dsi-on-command = [ + /* DSC Setting */ + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 C3 00 /* Scaler disable */ + 39 01 00 00 00 00 5A 0A /* PPS Setting (1440 x 3120) (initial value) */ + 10 00 00 89 30 80 0C 30 + 05 A0 00 41 02 D0 02 D0 + 02 00 02 C2 00 20 06 58 + 00 0A 00 0F 01 E0 01 2D + 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 + 00 + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + /* Common Setting */ + 15 00 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 2F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 0A B9 01 C0 3C 0B 00 00 00 11 03 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 45 /* FD setting (Normal mode) */ + 15 01 00 00 00 00 02 B5 48 + 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 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 1E + 39 01 00 00 00 00 06 C5 08 10 B4 24 FB /* FFC Setting; 0x08 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* OSC Spread Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 37 + 39 01 00 00 00 00 06 C5 04 FF 00 01 64 /* FFC Setting; 0x04 : Disable */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 15 01 00 00 00 00 02 B0 86 /* Global para */ + 15 01 00 00 00 00 02 EB 01 /* Dither IP Setting */ + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 D3 /* 0xD3 : ELVSS DIM ON */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-113mhz-osc-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-off-command=[ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 53 /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM Mode ON */ + 15 01 00 00 11 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 53 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 11 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + 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 = [ + /* ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 14 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 0D 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* 90Hz Setting */ + 15 01 00 00 11 00 02 53 30 /* 0x30 Normal transition(90Hz) */ + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 00 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + 15 01 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + ]; + 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-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-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 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 /* ELVSS Dim Setting */ + 15 00 00 00 00 00 02 B5 93 /* 0x93 : ELVSS DIM OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode Setting */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 27 /* HMB setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 4B + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 10 + 00 00 0F 03 06 02 0C 18 24 + 3C 77 00 FF 00 00 00 00 00 + 10 02 0C 18 24 3C 59 77 9B + BE E2 06 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 14 14 14 14 14 + 14 14 14 14 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 30 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + /* HBM MODE ON */ + 15 00 00 00 00 00 02 53 20 /* 0x20 Normal transition(60Hz) */ + 29 01 00 00 00 00 03 51 0F FF /* 600nit */ + /* HBM 670 ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 00 /* HBM_670 ON */ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* DLY ON */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 02 + 15 00 00 00 00 00 02 B5 13 /* DLY ON */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM 670 OFF */ + 29 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 92 02 /* HBM_670 OFF */ + 29 00 00 00 00 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 29 00 00 00 00 00 03 51 03 FF /* 430nit */ + 29 00 00 00 00 00 03 F0 5A 5A /* Level2 key Access */ + 15 00 00 00 00 00 02 C7 23 /* Normal setting */ + 15 00 00 00 00 00 02 B0 34 + 15 00 00 00 00 00 02 B1 6D + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 20 B1 40 + 00 00 1F 0F 18 08 30 60 90 + F0 DC FC FC 00 00 01 12 23 + 40 08 30 60 90 F0 66 DC 6C + FA 8A 18 + 15 00 00 00 00 00 02 B0 06 + 29 00 00 00 00 00 18 B5 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 50 50 50 50 50 + 50 50 50 50 + 15 00 00 00 00 00 02 B0 17 + 15 00 00 00 00 00 02 95 00 + 29 01 00 00 00 00 03 F0 A5 A5 /* Level2 key Access Disable */ + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command = [ + /*Level2 key Enable*/ + 29 01 00 00 00 00 03 F0 5A 5A + //07 01 00 00 00 00 01 01 + //29 00 00 00 00 00 05 2A 00 00 05 9F + //29 00 00 00 00 00 05 2B 00 00 0C 2F + /*OTP key Enable*/ + 29 01 00 00 00 00 03 F1 F1 A2 + 29 01 00 00 00 00 0D C1 00 00 00 06 00 00 00 00 00 00 00 05 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0C C1 00 00 00 01 40 02 00 00 00 00 10 + 15 01 00 00 00 00 02 C0 03 + 29 01 00 00 00 00 0E C1 00 00 00 6B 00 00 00 0A 00 00 00 05 01 + 15 01 00 00 00 00 02 B0 07 + ]; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command = [ + 15 01 00 00 00 00 02 C0 03 + 15 01 00 00 00 00 02 B0 08 + ]; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command = [ + /*13th Parameter : 1byte Read value*/ + 06 01 00 00 00 00 02 FB 00 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command = [ + 37 01 00 00 05 00 02 87 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command = [ + 06 01 00 00 00 00 02 C8 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command = [ + 37 01 00 00 00 00 02 B4 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command = [ + 06 01 00 00 00 00 02 C9 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command = [ + 37 01 00 00 00 00 02 2F 00 + ]; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command = [ + 06 01 00 00 00 00 02 B3 00 + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 E5 08 00 86 FF 00 04 03 F8 1B F0 E8 E9 03 ED DD F0 00 FF FE E4 + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 02 + 29 01 00 00 00 00 16 67 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 67 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-laoding-effect-enable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 81 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 FF 6D + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-laoding-effect-disable-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 02 95 A1 + 29 01 00 00 00 00 02 B0 14 + 29 01 00 00 00 00 03 95 28 28 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 EA 12 06 4A F4 14 09 02 BF 47 FC DC D3 0B E5 D2 F6 14 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 80 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 0A 00 02 B0 02 + 29 01 00 00 0A 00 16 67 FF 05 00 0B EB 00 07 00 FF 14 F8 EA F0 03 F5 DE F5 00 FF FF FF + 29 01 00 00 00 00 03 67 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-laoding-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-laoding-effect-disable-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_lp_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-gamma-flash-pre-read-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <720 720>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <65>; + 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; + }; + }; + }; +}; + +&dsi_samsung_oneplus_dsc_cmd_2nd { + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + 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-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-te-gpio = <&tlmm 67 0>; +}; + +&soc { + dsi_samsung_oneplus_dsc_cmd_2nd_display { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_oneplus_dsc_cmd_2nd { + //qcom,ulps-enabled; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { /* wqhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + }; + timing@1 { /* wqhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 09 06 03 04 00 1D 19]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<720 65 720 65 720 65>; + }; + }; +}; + 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 000000000000..e22abc27259e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef00_m_video.dtsi @@ -0,0 +1,116 @@ +/* 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>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 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","pw_bb_clk2"; + 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-samsung_sofef03f_m_fhd_dsc_cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef03f_m_fhd_dsc_cmd.dtsi new file mode 100644 index 000000000000..071946a5b64f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef03f_m_fhd_dsc_cmd.dtsi @@ -0,0 +1,915 @@ +/* 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_sofef03f_m_fhd_dsc_cmd: qcom,mdss_dsi_samsung_sofef03f_m_fhd_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung sofef03f_m 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-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 10>, <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,mdss-dsi-color-order = "rgb_swap_rgb"; + 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-lane-map = "lane_map_0123"; + 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-bl-min-level = <6>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-default-val = <160>; + 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-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-high-brightness-panel; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + /* 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 = <6800000>; + qcom,mdss-dsi-panel-average-brightness = <2000000>; + qcom,mdss-dsi-panel-blackness-level = <2000>; + qcom,mdss-dsi-panel-seria-num-year-index = <12>; + qcom,mdss-dsi-panel-seria-num-mon-index = <12>; + qcom,mdss-dsi-panel-seria-num-day-index = <13>; + qcom,mdss-dsi-panel-seria-num-hour-index = <14>; + qcom,mdss-dsi-panel-seria-num-min-index = <15>; + qcom,mdss-dsi-panel-seria-num-sec-index = <16>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [ + 06 01 00 00 00 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>; + + /* + * ************************************************************************************************************************ + * DMS (Dynamic Mode Switch) + * ************************************************************************************************************************ + */ + 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 = <1100000000>; + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-t-clk-post = <0x1A>; + 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-h-sync-pulse = <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-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-bl-pmic-control-type = "bl_ctrl_dcs"; + + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [ + 06 01 00 00 00 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-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 B6 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 = [ + /* 60hz �90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 /* 0x00 : 60 Hz */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 39 01 00 00 00 00 02 9D 01 /* Compression Enable */ + 39 01 00 00 00 00 81 9E /* PPS Setting */ + 11 00 00 89 30 80 09 60 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + + /* Common Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 /* TE Vsync On */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* PAGE ADDRESS SET */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* 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 + 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 02 B0 01 + 39 01 00 00 00 00 02 B7 53 /* 0x53 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Speed Control */ + 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 /* 0x01 : 1 Frames */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* TSP H_sync Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 DF 83 /* TSP H Sync ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 0A + 39 01 00 00 00 00 02 D5 05 /* FD Set Normal Mode */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* ERR_FG 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 05 EC 00 C2 C2 42 + 39 01 00 00 00 00 02 B0 0D + 39 01 00 00 00 00 02 EC 19 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OFC Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 E4 A6 C3 42 + 39 01 00 00 00 00 0F E9 11 75 A6 C3 42 96 2F 58 96 2F 58 00 32 32 + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + /* 60hz �90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 /* 0x00 : 60 Hz */ + 39 01 00 00 3C 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 02 28 00 + 05 01 00 00 64 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 BB + 39 00 00 00 00 00 02 BA 77 + 39 00 00 00 00 00 02 B0 01 + 39 00 00 00 00 00 03 B7 57 FF + 39 00 00 00 00 00 02 B0 0A + 39 00 00 00 00 00 11 B7 00 + 01 02 03 24 45 46 47 68 09 + 6A 8B 8C 40 A1 02 + 39 00 00 00 00 00 02 B0 3C + 39 00 00 00 00 00 1B B7 41 + 65 4A 67 E7 FF 80 08 55 8A + A9 54 9F EA A8 B5 2B FC CA + 6D 50 DF AE A4 F4 E0 + 39 01 00 00 11 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 00 00 00 00 00 02 53 20 + 39 01 00 00 11 00 03 51 03 FF + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 BB + 39 00 00 00 00 00 02 BA F7 + 39 00 00 00 00 00 02 B0 01 + 39 00 00 00 00 00 03 B7 52 A8 + 39 00 00 00 00 00 02 B0 0A + 39 00 00 00 00 00 11 B7 00 + 00 00 00 21 41 41 41 62 02 + 62 82 83 43 A3 03 + 39 00 00 00 00 00 02 B0 3C + 39 00 00 00 00 00 1B B7 2E + 23 2F 37 C3 C9 41 64 63 4B + 04 FD 54 A5 97 5E 46 31 67 + E6 CB 71 87 65 7B 20 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* 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 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 02 B0 01 + 39 01 00 00 00 00 02 B7 5B /* 0x5B : DLY OFF */ + 39 01 00 00 11 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 11 00 03 51 01 84 /* 670nit */ + /* Dimming Delay control */ + 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 02 B7 53 /* 0x53 : DLY ON */ + 39 01 00 00 07 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-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-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 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 02 B0 01 + 39 01 00 00 00 00 02 B7 5B /* 0x5B : DLY OFF */ + 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 00 00 03 51 01 84 /* 670nit */ + /* Dimming Delay control */ + 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 02 B7 53 /* 0x53 : 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-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 B1 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 39 01 00 00 00 00 02 81 90 + 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 E0 + 03 00 11 E2 01 0D 08 E5 1A + FA FC E5 09 F6 EA F3 01 FE + FF F7 + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 02 81 90 + 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 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 39 01 00 00 00 00 02 B1 00 + 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 06 C2 87 FF 6D C0 70 + 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 06 C2 A7 73 40 C0 30 + 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-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,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-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,panel-roi-alignment=<540 30 540 30 540 30>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <30>; + 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 = <1100000000>; + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-t-clk-post = <0x1A>; + 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-h-sync-pulse = <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-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-bl-pmic-control-type = "bl_ctrl_dcs"; + + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [ + 06 01 00 00 00 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-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 B6 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 = [ + /* 60hz �90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 /* 0x10 : 90 Hz */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 39 01 00 00 00 00 02 9D 01 /* Compression Enable */ + 39 01 00 00 00 00 81 9E /* PPS Setting */ + 11 00 00 89 30 80 09 60 + 04 38 00 1E 02 1C 02 1C + 02 00 02 0E 00 20 02 E3 + 00 07 00 0C 03 50 03 64 + 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 + + /* Sleep Out(11h) */ + 05 01 00 00 0A 00 01 11 + + /* Common Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 /* TE Vsync On */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* PAGE ADDRESS SET */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* 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 + 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 02 B0 01 + 39 01 00 00 00 00 02 B7 53 /* 0x53 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Speed Control */ + 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 /* 0x01 : 1 Frames */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* TSP H_sync Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 DF 83 /* TSP H Sync ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 0A + 39 01 00 00 00 00 02 D5 05 /* FD Set Normal Mode */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* ERR_FG 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 05 EC 00 C2 C2 42 + 39 01 00 00 00 00 02 B0 0D + 39 01 00 00 00 00 02 EC 19 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OFC Setting */ + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 E4 A6 C3 42 + 39 01 00 00 00 00 0F E9 11 75 A6 C3 42 96 2F 58 96 2F 58 00 32 32 + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + /* 60hz �90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 /* 0x10 : 90 Hz */ + 39 01 00 00 3C 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 02 28 00 + 05 01 00 00 64 00 02 10 00 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 BB + 39 00 00 00 00 00 02 BA 77 + 39 00 00 00 00 00 02 B0 01 + 39 00 00 00 00 00 03 B7 57 FF + 39 00 00 00 00 00 02 B0 0A + 39 00 00 00 00 00 11 B7 00 + 01 02 03 24 45 46 47 68 09 + 6A 8B 8C 40 A1 02 + 39 00 00 00 00 00 02 B0 3C + 39 00 00 00 00 00 1B B7 41 + 65 4A 67 E7 FF 80 08 55 8A + A9 54 9F EA A8 B5 2B FC CA + 6D 50 DF AE A4 F4 E0 + 39 01 00 00 0C 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 39 00 00 00 00 00 02 53 20 + 39 01 00 00 0C 00 03 51 03 FF + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 BB + 39 00 00 00 00 00 02 BA F7 + 39 00 00 00 00 00 02 B0 01 + 39 00 00 00 00 00 03 B7 52 A8 + 39 00 00 00 00 00 02 B0 0A + 39 00 00 00 00 00 11 B7 00 + 00 00 00 21 41 41 41 62 02 + 62 82 83 43 A3 03 + 39 00 00 00 00 00 02 B0 3C + 39 00 00 00 00 00 1B B7 2E + 23 2F 37 C3 C9 41 64 63 4B + 04 FD 54 A5 97 5E 46 31 67 + E6 CB 71 87 65 7B 20 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* 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 03 00 03 F0 A5 A5 + /* Dimming Delay control */ + 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 02 B7 5B /* 0x5B : DLY OFF */ + 39 01 00 00 0C 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 0C 00 03 51 01 84 /* 670nit */ + /* Dimming Delay control */ + 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 02 B7 53 /* 0x53 : 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-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-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 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 02 B0 01 + 39 01 00 00 00 00 02 B7 5B /* 0x5B : DLY OFF */ + 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 00 00 03 51 01 84 /* 670nit */ + /* Dimming Delay control */ + 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 02 B7 53 /* 0x53 : 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-panel-display-srgb-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-on-command = [ + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 B1 00 01 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 29 01 00 00 00 00 02 81 90 + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 02 B0 01 + 29 01 00 00 00 00 16 B1 F8 00 00 00 F0 00 05 00 EC 0A EA ED FD 01 F7 F1 EA 00 FF FE FE + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 39 01 00 00 00 00 02 81 90 + 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 E0 + 03 00 11 E2 01 0D 08 E5 1A + FA FC E5 09 F6 EA F3 01 FE + FF F7 + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 02 81 90 + 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 E0 03 00 11 E2 01 0D 08 E5 1A FA FC E5 09 F6 EA F3 01 FE FF F7 + 39 01 00 00 00 00 02 B1 00 + 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 06 C2 87 FF 6D C0 70 + 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 06 C2 A7 73 40 C0 30 + 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-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,mdss-dsi-customer-p3-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-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-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-panel-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-dci-p3-off-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-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-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-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,panel-roi-alignment=<540 30 540 30 540 30>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <30>; + 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_sofef03f_m_fhd_dsc_cmd { + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + 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,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&soc { + dsi_samsung_sofef03f_m_fhd_dsc_cmd_display { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_sofef03f_m_fhd_dsc_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0","pw_bb_clk2"; + qcom,mdss-dsi-display-timings { + timing@0 { /* fhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<540 30 540 30 540 30>; + }; + timing@1 { /* fhd 90hz */ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 0A 06 02 04 00 1E 1A]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment=<540 30 540 30 540 30>; + }; + }; +}; + + 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 000000000000..c78aa1c268ff --- /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 000000000000..08c6a928b60a --- /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 000000000000..54894686a0fa --- /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 000000000000..c909864db377 --- /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 000000000000..37330078b1ff --- /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 000000000000..06a95cadbd58 --- /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-qsync-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-cmd.dtsi new file mode 100644 index 000000000000..fae031cdfaa1 --- /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 000000000000..185f32603582 --- /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 000000000000..215b3ab46dde --- /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 000000000000..0268ded1a74c --- /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 000000000000..b0748f8d04a1 --- /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 000000000000..edb09ed0db4e --- /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 000000000000..ce0faca6452a --- /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 000000000000..6407ef2d75b2 --- /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 000000000000..ef10fbdcec12 --- /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 000000000000..9121f2cb8750 --- /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 000000000000..973dc517711c --- /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 000000000000..f5a522b0748e --- /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 000000000000..4d77525decb6 --- /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 000000000000..1c08e1931f81 --- /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 000000000000..ecac0d4bfc65 --- /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 000000000000..476c34c01d34 --- /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 000000000000..e9b7bac34504 --- /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 000000000000..49fdd7440a62 --- /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 000000000000..b3500c424d68 --- /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-xrsmrtvwr-jdi-dual-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-xrsmrtvwr-jdi-dual-video.dtsi new file mode 100644 index 000000000000..e6ce614d032b --- /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-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-alium-3600mah.dtsi new file mode 100644 index 000000000000..0be77e5406b6 --- /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 000000000000..5c8618c9dc9c --- /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 000000000000..f5e78e3a31d3 --- /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 000000000000..6b3aee7ec471 --- /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 000000000000..5c82394242a1 --- /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/instantnoodle-overlay-dvt.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-dvt.dts new file mode 100755 index 000000000000..7c6ad0a35418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-dvt.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodle.dtsi" +#include "camera/kona-oem-camera-instantnoodle.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP dvt 19821 19855 14 15"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19821 19855>; + /*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 15 55>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-evt1.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-evt1.dts new file mode 100755 index 000000000000..0a7e7e8c23e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-evt1.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodle.dtsi" +#include "camera/kona-oem-camera-instantnoodle.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP evt1 19821 19855 12 13"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19821 19855>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <12 13 54>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-t0.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-t0.dts new file mode 100755 index 000000000000..876fd00f95fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodle-overlay-t0.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodle.dtsi" +#include "camera/kona-oem-camera-instantnoodle.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP t0 19821 19855 11"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19821 19855>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <11>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodle.dtsi b/arch/arm64/boot/dts/vendor/qcom/instantnoodle.dtsi new file mode 100644 index 000000000000..84a4c12a7eee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodle.dtsi @@ -0,0 +1,347 @@ +/*this is for different project dtsi*/ +&kona_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 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", + "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"; +}; +&qupv3_se13_i2c { + status = "ok"; + sec-s6sy761@48 { + compatible = "sec-s6sy761"; + reg = <0x48>; + project-name = "19821"; + chip-name = "SY771"; + touchpanel,display-coords = <1079 2399>; + touchpanel,panel-coords = <1079 2399>; + touchpanel,tx-rx-num = <16 36>; + lcd_refresh_rate_switch = <1>; + panel = <&dsi_samsung_oneplus_dsc_cmd &dsi_samsung_ana6705_dsc_cmd + &dsi_samsung_ana6706_dsc_cmd>; + }; +}; + +/* @bsp, Battery & Charging config STRAT */ +&qupv3_se16_i2c { + oneplus_fastchg@26{ + op,4320mAh_4p45_support; + }; +}; + +&pm8150b_charger { + /* 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; + /* 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 = <225>; + op,sw-check-full-enable; + + /*ffc temp region*/ + ffc-pre-normal-decidegc = <120>; + ffc-normal-decidegc = <350>; + ffc-warm-decidegc = <400>; + ffc-normal-fcc-ma = <950>; + ffc-warm-fcc-ma = <1050>; + ffc-normal-cutoff-ma = <800>; + ffc-warm-cutoff-ma = <900>; + ffc-full-vbat-mv = <4480>; + + /* skin thermal temp adjust the dash current */ + op,skin-thermal-high-threshold = <41>; + op,skin-thermal-pre-high-threshold = <39>; + op,skin-thermal-medium-threshold = <38>; + op,skin-thermal-normal-threshold = <36>; + op,enable-dash-current-dynamic-adjust; + + /* skin thermal temp adjust the pd current */ + op,pd-skin-thermal-high-threshold = <38>; + op,pd-skin-thermal-normal-threshold = <36>; + op,enable-pd-current-dynamic-adjust; +}; + +&kona_mtp_batterydata { + #include "OP-fg-batterydata-4320mah.dtsi" +}; +/* @bsp, Battery & Charging config EDN */ + +/* @bsp, 2019/09/24 usb config START*/ +&usb2_phy0 { + qcom,param-override-seq = + <0x67 0x6c/*Disconnection voltage +21.56%*/ + 0x0b 0x70/*Pre-emphasis:4x DC voltage level:+17.80%*/ + 0x28 0x74>; +}; + +&usb1 { + status = "disabled"; +}; + +&thermal_zones { + skin_therm_19821: skin-therm { + trips { + skint_therm_trip0: skint_therm_trip0 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + skint_therm_trip1: skint_therm_trip1 { + temperature = <47000>; + hysteresis = <1000>; + type = "passive"; + }; + skint_therm_trip2: skint_therm_trip2 { + temperature = <48000>; + hysteresis = <2000>; + type = "passive"; + }; + skint_therm_trip3: skint_therm_trip3 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&skint_therm_trip0>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>;/*441.6*/ + }; + freq_dev1 { + trip = <&skint_therm_trip0>; + cooling-device = + <&CPU4 7 7>;/*1766*/ + }; + freq_dev2 { + trip = <&skint_therm_trip0>; + cooling-device = + <&CPU7 8 8>;/*2073*/ + }; + freq_dev3 { + trip = <&skint_therm_trip1>; + cooling-device = + <&CPU4 9 9>;/*1478*/ + }; + freq_dev4 { + trip = <&skint_therm_trip1>; + cooling-device = + <&CPU7 11 11>;/*1747*/ + }; + freq_dev5 { + trip = <&skint_therm_trip2>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-1) (THERMAL_MAX_LIMIT-1)>;/*400*/ + }; + freq_dev6 { + trip = <&skint_therm_trip2>; + cooling-device = + <&CPU0 3 3>;/*1516*/ + }; + freq_dev7 { + trip = <&skint_therm_trip2>; + cooling-device = + <&CPU4 14 14>;/*1056.0*/ + }; + freq_dev8 { + trip = <&skint_therm_trip2>; + cooling-device = + <&cpu7_isolate 1 1>; + }; + freq_dev9 { + trip = <&skint_therm_trip3>; + cooling-device = + <&CPU0 10 10>;/*883.2*/ + }; + freq_dev10 { + trip = <&skint_therm_trip3>; + cooling-device = + <&cpu4_isolate 1 1>; + }; + }; + }; + + msm_therm_19821: msm-therm { + trips { + msm_therm_trip0: msm_therm_trip0 { + temperature = <63000>; + hysteresis = <2000>; + type = "passive"; + }; + msm_therm_trip1: msm_therm_trip1 { + temperature = <65000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&msm_therm_trip0>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-3) (THERMAL_MAX_LIMIT-3)>;/*490(SVS_L1)*/ + }; + freq_dev1 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU0 2 2>;/*1612MHz(Nominal_L1)*/ + }; + freq_dev2 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU4 7 7>;/*1766.4MHz(Nominal_L1)*/ + }; + freq_dev3 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU7 8 8>;/*2073.6MHz(Nominal_L1)*/ + }; + freq_dev4 { + trip = <&msm_therm_trip1>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>;/*441.6(SVS_L0)*/ + }; + freq_dev5 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU0 3 3>;/*1516.8MHz(Nominal)*/ + }; + freq_dev6 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU4 9 9>;/*1574.4MHz(Nominal_L1)*/ + }; + freq_dev7 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU7 12 12>;/*1632.0MHz(Nominal)*/ + }; + }; + }; + +}; + +&vendor { + extcon_usb1 { + status = "disabled"; + }; +}; +/* @bsp, 2019/09/24 usb config END*/ diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-dvt.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-dvt.dts new file mode 100644 index 000000000000..519e20714a54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-dvt.dts @@ -0,0 +1,23 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlep.dtsi" +#include "instantnoodlep_dvt.dtsi" +#include "camera/kona-oem-camera-instantnoodlep_t0.dtsi" +/ { + model = "Qualcomm Technologies, Inc. kona MTP dvt/mp 19811 14 15 52 53"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19811>; + /*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 15 52 53>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evb.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evb.dts new file mode 100755 index 000000000000..74106b998780 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evb.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlep.dtsi" +#include "camera/kona-oem-camera-instantnoodlep_evb.dtsi" +/ { + model = "Qualcomm Technologies, Inc. kona MTP evb 19811 55"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19811>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <255>; /*only add no use value*/ +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evt1.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evt1.dts new file mode 100755 index 000000000000..5f7e26f4300e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-evt1.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlep.dtsi" +#include "camera/kona-oem-camera-instantnoodlep_t0.dtsi" +/ { + model = "Qualcomm Technologies, Inc. kona MTP evt1 19811 12 13 51"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19811>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <12 13 51>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-t0.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-t0.dts new file mode 100755 index 000000000000..9ee208d81497 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep-overlay-t0.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlep.dtsi" +#include "camera/kona-oem-camera-instantnoodlep_t0.dtsi" +/ { + model = "Qualcomm Technologies, Inc. kona MTP t0 19811 11"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19811>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <11>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep.dtsi b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep.dtsi new file mode 100644 index 000000000000..5748bdabb7e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep.dtsi @@ -0,0 +1,371 @@ +/*this is for different project dtsi*/ +/* @bsp, 2019/09/10 Wireless Charging porting STRAT */ +&op_wlchg { + status = "okay"; + op,max-voltage-mv = <4550>; + op,fastchg-curr-max-ma = <1500>; + op,fastchg-curr-min-ma = <400>; + op,fastchg-vol-entry-max-mv = <4380>; + op,fastchg-vol-normal-max-mv = <4480>; + op,fastchg-vol-hot-max-mv = <4130>; + op,fastchg-vol-min-mv = <3300>; + op,fastchg-temp-max = <430>; + op,fastchg-temp-min = <120>; + op,fastchg-soc-max = <85>; + op,fastchg-soc-min = <1>; + op,fastchg-soc-mid = <75>; + op,fastchg-discharge-curr-max = <2000>; + /* + * | temp_min | temp_max | target_curr_ua | vol_max_mv |need wait | + * + * temp_min: Switch to the previous level when the temperature is lower + * than this value. If it is 0, do not switch. + * temp_max: Switch to the next level when the temperature is greater + * than this value + * target_curr_ua: Target current in this temperature range. + * vol_max_mv: Maximum battery voltage. + * need wait: 1:Need wait for a while after switching to the next level. + * 0:No need to wait after switching to the next level. + */ + op,fastchg-ffc_step = <0 405 1500000 4420 1 + 380 420 1000000 4450 1 + 390 420 850000 4480 1 + 400 420 625000 4480 0>; + /* ibatmax setting for different temp regions */ + op,epp-ibatmax-ma = <0 1000 2500 2500 2500 2500 1500 0>; + op,bpp-ibatmax-ma = <0 1000 1500 1500 1500 1500 1500 0>; + op,bpp-sdp-ibatmax-ma = <0 1000 1000 1000 1000 1000 1000 0>; + op,epp-iclmax-ma = <0 300 1100 1100 1100 1100 650 0>; + op,bpp-iclmax-ma = <0 500 1000 1000 1000 1000 1000 0>; + op,bpp-sdp-iclmax-ma = <0 500 500 500 500 500 500 0>; + op,fastchg-ibatmax-ma = <4000 6000>; + /* 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 = <440>; + hot-bat-decidegc = <500>; + + cool-vbat-thr-mv = <4180>; + cool-epp-ibat-ma = <1500>; + cool-epp-icl-ma = <650>; + /* deviation check */ + op,rx-freq-threshold = <129>; + + /*wireless charge skin-therm*/ + fastchg-skin-temp-max = <420>; + fastchg-skin-temp-min = <400>; + epp-skin-temp-max = <390>; + epp-skin-temp-min = <370>; + op,epp-curr-step = <1100 550>; + + /* fod parameter*/ + op,fastchg-fod-enable; + op,fastchg-match-q = /bits/ 8 <0x44>; + op,fastchg-fod-parm = /bits/ 8 <0xac 0x32 0xac 0x28 0xa0 0x1e + 0x9a 0x37 0x9a 0x32 0x9f 0xc4>; + op,fastchg-fod-parm-startup = /bits/ 8 <0xac 0x7f 0xac 0x28 0xa0 0x1e + 0x9a 0x37 0x9a 0x32 0x9f 0xc4>; + + /* vbatdet setting for different temp regions */ + vbatdet-mv = <0 3675 4235 4370 4370 4370 4030 0>; +}; + +&op_wlchg_rx { + status = "okay"; +}; + +&op_wlchg_cp1 { + status = "okay"; +}; + +&op_wlchg_cp2 { + status = "okay"; +}; + +&op_wlchg_gpio { + status = "okay"; +}; + +&op_wlchg_pm8250_gpio { + status = "okay"; +}; + +&op_wlchg_pm8150a_gpio { + status = "okay"; +}; + +&pm8150b_pdphy { + pinctrl-names = "default"; + pinctrl-0 = <&vbus_gpio_default>; + otg-use_external_boost; + otg_en-gpio = <&pm8150l_gpios 4 0x00>; + vbus-gpio = <&tlmm 172 0x00>; +}; +/* @bsp, 2019/09/10 Wireless Charging porting END */ +&qupv3_se13_i2c { + status = "ok"; + sec-s6sy761@48 { + compatible = "sec-s6sy761"; + reg = <0x48>; + project-name = "19811"; + chip-name = "SY79x"; + touchpanel,display-coords = <1439 3168>; + touchpanel,panel-coords = <1439 3168>; + touchpanel,tx-rx-num = <17 38>; + wireless_charge_support = <1>; + audio_noise_support = <1>; + project_info = <1>; + panel = <&dsi_samsung_oneplus_dsc_cmd + &dsi_samsung_ana6706_dsc_cmd &dsi_samsung_ana6705_dsc_cmd>; + }; +}; + +/* @bsp, Battery & Charging config STRAT */ +&qupv3_se16_i2c { + oneplus_fastchg@26{ + op,4510mAh_4p45_support; + }; +}; + +&pm8150b_charger { + /* 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 = <1200>; + ibatmax-little-cool-thr-ma = <1900>; + ibatmax-cool-thr-ma = <1200>; + /* 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; + /* 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 = <235>; + op,sw-check-full-enable; + + /*ffc temp region*/ + ffc-pre-normal-decidegc = <120>; + ffc-normal-decidegc = <350>; + ffc-warm-decidegc = <400>; + ffc-normal-fcc-ma = <1000>; + ffc-warm-fcc-ma = <1050>; + ffc-normal-cutoff-ma = <850>; + ffc-warm-cutoff-ma = <900>; + ffc-full-vbat-mv = <4480>; + + /* skin thermal temp adjust the dash current */ + op,skin-thermal-high-threshold = <41>; + op,skin-thermal-pre-high-threshold = <39>; + op,skin-thermal-medium-threshold = <38>; + op,skin-thermal-normal-threshold = <36>; + op,enable-dash-current-dynamic-adjust; + + /* skin thermal temp adjust the pd current */ + op,pd-skin-thermal-high-threshold = <39>; + op,pd-skin-thermal-normal-threshold = <37>; + op,enable-pd-current-dynamic-adjust; +}; + +&kona_mtp_batterydata { + #include "OP-fg-batterydata-4510mah.dtsi" +}; +/* @bsp, Battery & Charging config END */ + +/* @bsp, 2019/10/08 usb config START*/ +&usb2_phy0 { + qcom,param-override-seq = + <0x67 0x6c/*Disconnection voltage +21.56%*/ + 0x0b 0x70/*Pre-emphasis:4x DC voltage level:+17.80%*/ + 0x28 0x74>; +}; + +&usb1 { + status = "disabled"; +}; + +&thermal_zones { + skin-therm { + trips { + freq_config0: freq_config0 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + freq_config1: freq_config1 { + temperature = <47000>; + hysteresis = <1000>; + type = "passive"; + }; + freq_config2: freq_config2 { + temperature = <49000>; + hysteresis = <2000>; + type = "passive"; + }; + freq_config3: freq_config3 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&freq_config1>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-1) (THERMAL_MAX_LIMIT-1)>;/*345*/ + }; + freq_dev1 { + trip = <&freq_config0>; + cooling-device = + <&CPU4 7 7>;/*1766*/ + }; + freq_dev2 { + trip = <&freq_config0>; + cooling-device = + <&CPU7 8 8>;/*2073*/ + }; + freq_dev3 { + trip = <&freq_config1>; + cooling-device = + <&CPU0 2 2>;/*1612*/ + }; + freq_dev4 { + trip = <&freq_config1>; + cooling-device = + <&CPU4 10 10>;/*1478*/ + }; + freq_dev5 { + trip = <&freq_config1>; + cooling-device = + <&CPU7 17 17>;/*1075*/ + }; + freq_dev7 { + trip = <&freq_config2>; + cooling-device = + <&CPU0 3 3>;/*1516*/ + }; + freq_dev8 { + trip = <&freq_config2>; + cooling-device = + <&CPU4 14 14>;/*1056*/ + }; + freq_dev9 { + trip = <&freq_config2>; + cooling-device = + <&cpu7_isolate 1 1>; + }; + freq_dev10 { + trip = <&freq_config3>; + cooling-device = + <&CPU0 10 10>;/*883*/ + }; + freq_dev11 { + trip = <&freq_config3>; + cooling-device = + <&cpu4_isolate 1 1>; + }; + }; + }; + + msm-therm { + trips { + freq_config4: freq_config4 { + temperature = <67000>; + hysteresis = <2000>; + type = "passive"; + }; + freq_config5: freq_config5 { + temperature = <69000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&freq_config4>; + cooling-device = + <&CPU0 2 2>;/*1612 17*/ + }; + freq_dev1 { + trip = <&freq_config4>; + cooling-device = + <&CPU4 7 7>;/*1766 18*/ + }; + freq_dev2 { + trip = <&freq_config4>; + cooling-device = + <&CPU7 8 8>;/*2073 20*/ + }; + freq_dev3 { + trip = <&freq_config5>; + cooling-device = + <&CPU0 3 3>;/*1382*/ + }; + freq_dev4 { + trip = <&freq_config5>; + cooling-device = + <&CPU4 4 4>;/*1748*/ + }; + freq_dev5 { + trip = <&freq_config5>; + cooling-device = + <&CPU7 11 11>;/*1747*/ + }; + freq_dev6 { + trip = <&freq_config4>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>;/*441*/ + }; + freq_dev7 { + trip = <&freq_config5>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>;/*400*/ + }; + }; + }; + +}; + +&vendor { + extcon_usb1 { + status = "disabled"; + }; +}; +/* @bsp, 2019/10/08 usb config END*/ diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlep_dvt.dtsi b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep_dvt.dtsi new file mode 100644 index 000000000000..c28ab6953869 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlep_dvt.dtsi @@ -0,0 +1,39 @@ +/*this is for one project different hw version */ +&op_wlchg { + qcom,dcdc_en-gpio = <&pm8150b_gpios 5 0x00>; + pinctrl-names = "wrx_en_active", "wrx_en_sleep", "wrx_en_default", + "wrx_otg_active", "wrx_otg_sleep", + "usbin_int_active", "usbin_int_sleep", "usbin_int_default", + "dcdc_en_active", "dcdc_en_sleep", "dcdc_en_default"; + pinctrl-8 = <&dcdc_en_active>; + pinctrl-9 = <&dcdc_en_sleep>; + pinctrl-10 = <&dcdc_en_default>; + op-ap_control_dcdc; +}; + +&pm8150b_gpios { + dcdc_en_active: dcdc_en_active { + pins = "gpio5"; /* GPIO 5 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-high; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + }; + dcdc_en_sleep: dcdc_en_sleep { + pins = "gpio5"; /* GPIO 5 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + }; + dcdc_en_default: dcdc_en_default { + pins = "gpio5"; /* GPIO 5 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-dvt.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-dvt.dts new file mode 100755 index 000000000000..2bc31a05bc58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-dvt.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlev.dtsi" +#include "camera/kona-oem-camera-instantnoodlev_evt1.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP dvt 19867 14 15"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19867 >; + /*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 15>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-evt1.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-evt1.dts new file mode 100755 index 000000000000..de5974e34be7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-evt1.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlev.dtsi" +#include "camera/kona-oem-camera-instantnoodlev_evt1.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP evt1 19867 12 13"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19867>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <12 13>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-t0.dts b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-t0.dts new file mode 100755 index 000000000000..3df694fc31fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev-overlay-t0.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" +#include "kona-oem.dtsi" +#include "instantnoodlev.dtsi" +#include "camera/kona-oem-camera-instantnoodlev.dtsi" /* camera maybe use the same */ +/ { + model = "Qualcomm Technologies, Inc. kona MTP t0 19867 11"; + compatible = "qcom,kona-mtp", "qcom,kona", "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 = <19867>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <11>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/instantnoodlev.dtsi b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev.dtsi new file mode 100644 index 000000000000..74a5c834a71e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/instantnoodlev.dtsi @@ -0,0 +1,388 @@ +/*this is for different project dtsi*/ +#include "instantnoodle.dtsi" +#include "kona-thermal.dtsi" +/* @bsp, Battery & Charging config STRAT */ +&qupv3_se16_i2c { + oneplus_fastchg@26{ + op,4300mAh_4p45_support; + }; +}; + +&pm8150b_charger { + /* 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; + /* 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 = <225>; + op,sw-check-full-enable; + + /*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 = <880>; + ffc-warm-cutoff-ma = <950>; + ffc-full-vbat-mv = <4480>; + + /* skin thermal temp adjust the dash current */ + op,skin-thermal-high-threshold = <41>; + op,skin-thermal-pre-high-threshold = <39>; + op,skin-thermal-medium-threshold = <38>; + op,skin-thermal-normal-threshold = <36>; + op,enable-dash-current-dynamic-adjust; + + /* skin thermal temp adjust the pd current */ + op,pd-skin-thermal-high-threshold = <38>; + op,pd-skin-thermal-normal-threshold = <36>; + op,enable-pd-current-dynamic-adjust; + op,slowy-charge-check; +}; + +&kona_mtp_batterydata { + #include "OP-fg-batterydata-4300mah.dtsi" +}; +/* @bsp, Battery & Charging config STRAT */ + +/delete-node/ &skin_therm_19821; +/delete-node/ &msm_therm_19821; + +&thermal_zones { + skin-therm-usr { //modem_skin MDM + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + skin_therm_usr_trip0: skin_therm_usr_trip0 { + temperature = <50000>; + hysteresis = <7000>; + type = "passive"; + }; + skin_therm_usr_trip1: skin_therm_usr_trip1 { + temperature = <54000>; + hysteresis = <9000>; + type = "passive"; + }; + skin_therm_usr_trip3: skin_therm_usr_trip3 { + temperature = <58000>; + hysteresis = <7000>; + type = "passive"; + }; + }; + cooling-maps { + modem_Tj_lvl1 { + trip = <&skin_therm_usr_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + modem_skin_lvl1 { + trip = <&skin_therm_usr_trip1>; + cooling-device = <&modem_skin 1 1>; + }; + modem_skin_lvl3 { + trip = <&skin_therm_usr_trip3>; + cooling-device = <&modem_skin 3 3>; + }; + }; + }; + + mmw-pa1-usr { //mmw_skin0 QTM0 + 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_pa1_usr_trip0: mmw_pa1_usr_trip0 { + temperature = <48000>; + hysteresis = <5000>; + type = "passive"; + }; + mmw_pa1_usr_trip1: mmw_pa1_usr_trip1 { + temperature = <50000>; + hysteresis = <5000>; + type = "passive"; + }; + mmw_pa1_usr_trip2: mmw_pa1_usr_trip2 { + temperature = <52000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + mmw_skin0_lvl1 { + trip = <&mmw_pa1_usr_trip0>; + cooling-device = <&modem_mmw_skin0 1 1>; + }; + mmw_skin0_lvl2 { + trip = <&mmw_pa1_usr_trip1>; + cooling-device = <&modem_mmw_skin0 2 2>; + }; + mmw_skin0_lvl3 { + trip = <&mmw_pa1_usr_trip2>; + cooling-device = <&modem_mmw_skin0 3 3>; + }; + }; + }; + + xo-therm-usr { //mmw_skin1 QTM1 + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + xo_therm_usr_trip0: xo_therm_usr_trip0 { + temperature = <56000>; + hysteresis = <5000>; + type = "passive"; + }; + xo_therm_usr_trip1: xo_therm_usr_trip1 { + temperature = <58000>; + hysteresis = <5000>; + type = "passive"; + }; + xo_therm_usr_trip2: xo_therm_usr_trip2 { + temperature = <60000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + mmw_skin1_lvl1 { + trip = <&xo_therm_usr_trip0>; + cooling-device = <&modem_mmw_skin1 1 1>; + }; + mmw_skin1_lvl2 { + trip = <&xo_therm_usr_trip1>; + cooling-device = <&modem_mmw_skin1 2 2>; + }; + mmw_skin1_lvl3 { + trip = <&xo_therm_usr_trip2>; + cooling-device = <&modem_mmw_skin1 3 3>; + }; + }; + }; + + modem-mmw2-usr { //mmw2 QTM2 + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_2)>; + wake-capable-sensor; + trips { + modem_mmw2_usr_trip0: modem_mmw2_usr_trip0{ + temperature = <56000>; + hysteresis = <5000>; + type = "passive"; + }; + modem_mmw2_usr_trip1: modem_mmw2_usr_trip1{ + temperature = <58000>; + hysteresis = <5000>; + type = "passive"; + }; + modem_mmw2_usr_trip2: modem_mmw2_usr_trip2{ + temperature = <60000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + mmw2_lvl1 { + trip = <&modem_mmw2_usr_trip0>; + cooling-device = <&modem_mmw2 1 1>; + }; + mmw2_lvl2 { + trip = <&modem_mmw2_usr_trip1>; + cooling-device = <&modem_mmw2 2 2>; + }; + mmw2_lvl3 { + trip = <&modem_mmw2_usr_trip2>; + cooling-device = <&modem_mmw2 3 3>; + }; + }; + }; + + skin_therm_19867: skin-therm{ + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + skint_therm_trip0: skint_therm_trip0 { + temperature = <44000>; + hysteresis = <2000>; + type = "passive"; + }; + skint_therm_trip1: skint_therm_trip1 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + skint_therm_trip2: skint_therm_trip2 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&skint_therm_trip0>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>;/*441.6(SVS_L0)*/ + }; + freq_dev1 { + trip = <&skint_therm_trip0>; + cooling-device = + <&CPU0 3 3>;/*1516.8MHz(Nominal)*/ + }; + freq_dev2 { + trip = <&skint_therm_trip0>; + cooling-device = + <&CPU4 9 9>;/*1574.4MHz(Nominal_L1)*/ + }; + freq_dev3 { + trip = <&skint_therm_trip0>; + cooling-device = + <&CPU7 12 12>;/*1632.0MHz(Nominal)*/ + }; + freq_dev4 { + trip = <&skint_therm_trip1>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-1) (THERMAL_MAX_LIMIT-1)>;/*400(SVS)*/ + }; + freq_dev5 { + trip = <&skint_therm_trip1>; + cooling-device = + <&CPU0 5 5>;/*1344MHz(Nominal)*/ + }; + freq_dev6 { + trip = <&skint_therm_trip1>; + cooling-device = + <&CPU4 14 14>;/*1056Mhz(SVS_L1)*/ + }; + freq_dev7 { + trip = <&skint_therm_trip1>; + cooling-device = + <&cpu7_isolate 1 1>; /*Disable(cpu7_isolate 1 1)*/ + }; + freq_dev8 { + trip = <&skint_therm_trip2>; + cooling-device = + <&CPU0 10 10>;/*883.2Mhz(SVS)*/ + }; + freq_dev9 { + trip = <&skint_therm_trip2>; + cooling-device = + <&cpu4_isolate 1 1>; /*Disable(cpu4_isolate 1 1)*/ + }; + }; + }; + + msm_therm_19867: 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; + trips { + msm_therm_trip0: msm_therm_trip0 { + temperature = <63000>; + hysteresis = <2000>; + type = "passive"; + }; + msm_therm_trip1: msm_therm_trip1 { + temperature = <65000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + cooling-maps { + freq_dev0 { + trip = <&msm_therm_trip0>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-3) (THERMAL_MAX_LIMIT-3)>;/*490(SVS_L1)*/ + }; + freq_dev1 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU0 2 2>;/*1612MHz(Nominal_L1)*/ + }; + freq_dev2 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU4 7 7>;/*1766.4MHz(Nominal_L1)*/ + }; + freq_dev3 { + trip = <&msm_therm_trip0>; + cooling-device = + <&CPU7 8 8>;/*2073.6MHz(Nominal_L1)*/ + }; + freq_dev4 { + trip = <&msm_therm_trip1>; + cooling-device = + <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>;/*441.6(SVS_L0)*/ + }; + freq_dev5 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU0 3 3>;/*1516.8MHz(Nominal)*/ + }; + freq_dev6 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU4 9 9>;/*1574.4MHz(Nominal_L1)*/ + }; + freq_dev7 { + trip = <&msm_therm_trip1>; + cooling-device = + <&CPU7 12 12>;/*1632.0MHz(Nominal)*/ + }; + }; + }; +}; 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 000000000000..b4bfb42ce4ca --- /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 000000000000..b4bfb42ce4ca --- /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 000000000000..e442628c74b6 --- /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 000000000000..8d9823518cb4 --- /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 000000000000..ae746f1b00a5 --- /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 000000000000..a7306484d3c7 --- /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 000000000000..5e4e20cb37d6 --- /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 000000000000..d1e2288d4441 --- /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 000000000000..a73e6a220bf6 --- /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 000000000000..ad04489c9e11 --- /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 000000000000..d593aec82a71 --- /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 000000000000..242827f3925e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dtsi @@ -0,0 +1,833 @@ +#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>; + }; +}; + +&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>; +}; + +&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 000000000000..b5c7e5625187 --- /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 000000000000..460cd4ac47ff --- /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 000000000000..12af820076ee --- /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 000000000000..4368a5fa1424 --- /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 000000000000..0c62e71330e2 --- /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 000000000000..cc56bb53076f --- /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 000000000000..610d9f317414 --- /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 000000000000..7d658cf4cb11 --- /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 000000000000..66c579d91546 --- /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 000000000000..7dcb3610a818 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mhi.dtsi @@ -0,0 +1,775 @@ +&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>; + /* Case 0449153 - Reduce tiemout from 2000 to 500 ms for shutdown performance */ + mhi,timeout = <500>; + 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 = <0>; + 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 000000000000..1928b89ca808 --- /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-ws-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws-overlay.dts new file mode 100644 index 000000000000..778ed9b64c04 --- /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 000000000000..bffdb81d8672 --- /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 000000000000..362c9fd2e674 --- /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 000000000000..2b12870bcee7 --- /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 000000000000..25234ac1337c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dtsi @@ -0,0 +1,675 @@ +#include +#include + +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.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 109 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" + }; +}; + +&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>; + }; + + skin_therm@4d { + reg = ; + label = "skin_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" +}; + +&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>, + <&pm8150b_vadc ADC_AMUX_THM1_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + 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"; + }; + }; + }; + + skin-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + }; + + 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-flash-therm { + 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"; + }; + }; + }; + /*Origin is skin-msm-therm-usr*/ + 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-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"; +}; + +&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 000000000000..17d6e025cfdb --- /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-oem.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-oem.dtsi new file mode 100644 index 000000000000..8cb1aeaf79a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-oem.dtsi @@ -0,0 +1,1664 @@ +/*this is for oem project dtsi*/ +&soc { + tri_state_key:tri_state_key { + compatible = "oneplus,hall_tri_state_key"; + status = "ok"; + interrupt-parent = <&tlmm>; + }; + + bootloader_log { + compatible = "bootloader_log"; + linux,contiguous-region = <&bootloader_log_mem>; + }; + + fingerprint_detect:fingerprint_detect { + compatible = "oneplus,fpdetect"; + fp-gpio-id0 = <&tlmm 77 0>; + pinctrl-names = "fp_id_init"; + pinctrl-0 = <&fp_id0_init>; + }; + + goodix_fp { + compatible = "goodix,fingerprint"; + interrupt-parent = <&tlmm>; + //vdd-3v2-supply = <&pm8998_l22>; + //vdd-voltage = <3200000 3200000>; + //vdd-current = <50000>; + fp-gpio-irq = <&tlmm 23 0x00>; + fp-gpio-reset = <&tlmm 68 0x00>; + fp-gpio-enable = <&tlmm 125 0x00>; + pinctrl-names = "fp_en_init", "fp_dis_init"; + pinctrl-0 = <&fp_vdd_init &fp_irq_init>; + pinctrl-1 = <&fp_vdd_dis_init>; + status = "okay"; + }; + + qcom,qbt_handler { + status = "disabled"; + }; +}; + +&vendor { + /delete-node/ extcon_usb1; +}; + + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <400000>; + ist8801@19 { + compatible = "oneplus,hall-ist8801,up"; + reg = <0x19>; + dhall,id = <1>; + vdd-supply = <&pm8150a_l10>; + interrupt-parent = <&tlmm>; + interrups = <157 0x02>; + dhall,irq-gpio = <&tlmm 157 0x2008>; + pinctrl-names = "ist8801_hall_up_active"; + pinctrl-0 = <&ist8801_hall_up_active>; + }; + ist8801@18 { + compatible = "oneplus,hall-ist8801,down"; + reg = <0x18>; + dhall,id = <2>; + vdd-supply = <&pm8150a_l10>; + interrupt-parent = <&tlmm>; + interrups = <158 0x02>; + dhall,irq-gpio = <&tlmm 158 0x2008>; + pinctrl-names = "ist8801_hall_down_active"; + pinctrl-0 = <&ist8801_hall_down_active>; + }; +}; +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <400000>; + magnachip@0D { + compatible = "tri_key_magnachip,tk_mxm1120,up"; + reg = <0x0D>; + vdd-supply = <&pm8150a_l10>; + magnachip,init-interval = <200>; + interrupt-parent = <&tlmm>; + interrups = <157 0x02>; + dhall,irq-gpio = <&tlmm 157 0x2008>; + pinctrl-names = "uphall_tri_state_key_active"; + pinctrl-0 = <&uphall_tri_state_key_active>; + }; + magnachip@0C { + compatible = "tri_key_magnachip,tk_mxm1120,down"; + reg = <0x0C>; + vdd-supply = <&pm8150a_l10>; + magnachip,init-interval = <200>; + interrupt-parent = <&tlmm>; + interrups = <158 0x02>; + dhall,irq-gpio = <&tlmm 158 0x2008>; + pinctrl-names = "downhall_tri_state_key_active"; + pinctrl-0 = <&downhall_tri_state_key_active>; + }; +}; + +&qupv3_se2_i2c { + status = "ok"; + qcom,clk-freq-out = <400000>; + pixelworks@26 { //i2c: 22, i3c: 26 + status = "ok"; + compatible = "pixelworks,iris"; + reg = <0x26>; + }; + + pixelworks@22 { //i2c: 22, i3c: 26 + status = "ok"; + compatible = "pixelworks,iris-i2c"; + reg = <0x22>; + }; +}; + + +&tlmm { + uphall_tri_state_key_active: uphall_tri_state_key_active { + mux { + pins = "gpio157"; + function = "gpio"; + }; + config { + pins = "gpio157"; + drive-strength = <2>; + bias-pull-up; + }; + }; + downhall_tri_state_key_active: downhall_tri_state_key_active { + mux { + pins = "gpio158"; + function = "gpio"; + }; + config { + pins = "gpio158"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; +&tlmm { + ist8801_hall_up_active: ist8801_hall_up_active { + mux { + pins = "gpio157"; + function = "gpio"; + }; + config { + pins = "gpio157"; + drive-strength = <2>; + bias-pull-up; + }; + }; + ist8801_hall_down_active: ist8801_hall_down_active { + mux { + pins = "gpio158"; + function = "gpio"; + }; + config { + pins = "gpio158"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + fp_irq_init: fp_irq_init { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + fp_vdd_init: fp_vdd_init { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + fp_vdd_dis_init: fp_vdd_dis_init { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <8>; + bias-pull-down; + output-low; + }; + }; + + fp_id0_init: fp_id0_init { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-disable; /* No Pull */ + input-enable; + }; + }; + + fp_reset_init: fp_reset_init { + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + drive-strength = <8>; + bias-pull-up; + }; + }; +}; +&qupv3_se13_i2c { + status = "ok"; + sec-s6sy761@48 { + compatible = "sec-s6sy761"; + reg = <0x48>; + project-name = "19811"; + chip-name = "SY761"; + module_id = <7>; + reset-gpio = <&tlmm 38 0x00>; + irq-gpio = <&tlmm 39 0x2008>; + vdd_2v8-supply = <&pm8150_l13>; //set 3.3 by ldo + vdd_2v8_volt = <3008000>; + vcc_1v8-supply = <&pm8150a_l1>; + // enable1v8_gpio = <&tlmm 119 0x00>; //set 1.8v by + touchpanel,display-coords = <1439 3119>; + touchpanel,panel-coords = <1439 3119>; + touchpanel,tx-rx-num = <17 37>; + //edge_limit_support = <1>; + //spurious_fingerprint_support = <1>; + //charger_pump_support = <1>; + black_gesture_support = <1>; + //black_gesture_test_support = <1>; + game_switch_support = <1>; + face_detect_support = <1>; + touch_hold_support = <1>; + touchpanel,max-num-support = <10>; + charge_detect_support = <1>; + //lcd_trigger_fp_check = <1>; + module_id_support = <1>; + pinctrl-names = "pin_set_high", "pin_set_low"; + pinctrl-0 = <&tp_irq_active &tp_rst_active>; + pinctrl-1 = <&tp_rst_suspend>; + //touchpanel,int-mode = <1>; + }; +}; +&qupv3_se13_i2c { + status = "ok"; + synaptics-s3908@4B { + compatible = "synaptics-s3908"; + reg = <0x4B>; + project-name = "19821"; + chip-name = "S3908"; + module_id = <7>; + reset-gpio = <&tlmm 38 0x00>; + irq-gpio = <&tlmm 39 0x2008>; + vdd_2v8-supply = <&pm8150_l13>; //set 3.3 by ldo + vdd_2v8_volt = <3008000>; + vcc_1v8-supply = <&pm8150a_l1>; + touchpanel,display-coords = <1079 2399>; + touchpanel,panel-coords = <1079 2399>; + touchpanel,tx-rx-num = <16 36>; + //edge_limit_support = <1>; + //spurious_fingerprint_support = <1>; + //charger_pump_support = <1>; + black_gesture_support = <1>; + //black_gesture_test_support = <1>; + //game_switch_support = <1>; + face_detect_support = <1>; + touch_hold_support = <1>; + touchpanel,max-num-support = <10>; + pinctrl-names = "pin_set_high", "pin_set_low"; + pinctrl-0 = <&tp_irq_active &tp_rst_active>; + pinctrl-1 = <&tp_rst_suspend>; + touchpanel,int-mode = <1>; + panel = <&dsi_boe_nt37800_fhd_dsc_cmd>; + }; +}; +&tlmm { + tp_irq_active: tp_irq_active { + mux { + pins = "gpio39"; + function = "gpio"; + }; + config { + pins = "gpio39"; + drive-strength = <8>; + bias-disable; + input-enable; + }; + }; + tp_rst_active: tp_rst_active { + mux { + pins = "gpio38"; + function = "gpio"; + }; + config { + pins = "gpio38"; + drive-strength = <8>; + bias-pull-up; + }; + }; + tp_rst_suspend: tp_rst_suspend { + mux { + pins = "gpio38"; + function = "gpio"; + }; + config { + pins = "gpio38"; + drive-strength = <8>; + bias-pull-down; + }; + }; +}; + +&pil_adsp_mem { + reg = <0x0 0x8fe00000 0x0 0x2500000>; +}; + +&pil_spss_mem { + reg = <0x0 0x92300000 0x0 0x100000>; +}; + +&cdsp_secure_heap { + reg = <0x0 0x92400000 0x0 0x4600000>; +}; + +&spss_utils { + qcom,pil-addr = <0x92300000>; // backward compatible +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; + +&wsa881x_0211 { + status = "disabled"; +}; + +&wsa881x_0212 { + status = "disabled"; +}; + +&wsa881x_0213 { + status = "disabled"; +}; + +&wsa881x_0214 { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; + +&qupv3_se15_i2c { + tfa98xx_right: tfa98xx_right@34 { + compatible = "nxp,tfa98xx"; + reg = <0x34>; + reset-gpio = <&tlmm 91 0>; + status = "ok"; + }; + + tfa98xx_left: tfa98xx_left@35 { + compatible = "nxp,tfa98xx"; + reg = <0x35>; + reset-gpio = <&tlmm 99 0>; + status = "ok"; + }; + + nq@64 { + status = "disabled"; + }; +}; + +&dai_mi2s2 { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; +}; + +&cdc_tert_mi2s_gpios { + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active &tert_mi2s_sd1_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep &tert_mi2s_sd1_sleep>; +}; + +&fsa4480 { + reg = <0x42>; +}; + +&wcd938x_codec { + qcom,cdc-vdd-mic-bias-voltage = <3300000 3600000>; + qcom,cdc-micbias2-mv = <2700>; +}; + +&swr0 { + status = "disabled"; +}; + +&tlmm { + mbhc_en_output_high: mbhc_en_output_high { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + output-high; + bias-pull-down; + }; + }; + + mbhc_en_output_low: mbhc_en_output_low { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + output-low; + bias-pull-down; + }; + }; +}; + +&kona_snd { + //enable low-latency loopback + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback1>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + qcom,afe-rxtx-lb = <1>; + // default audio routing for 3-mic + 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 BIAS4", + "MIC BIAS4", "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", + "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 BIAS4", "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 BIAS4", + "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,wsa-max-devs = <0>; + qcom,wsa-devs; + //qcom,codec-aux-devs = <-2>; + + //qcom,tert-mi2s-gpios = <&tert_mi2s_gpios>; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-use-usbc-detect = <1>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <2550>; + + pinctrl-names = "hs_det_default"; + pinctrl-0 = <&mbhc_en_output_low>; +}; + +&reserved_memory { + + bootloader_log_mem: bootloader_log_mem@0x9FFF7000 { + reg = <0 0x9FFF7000 0 0x00009000>; + label = "bootloader_log_mem"; + }; + + param_mem: param_mem@ac200000 { + reg = <0 0xAC200000 0 0x00100000>; + label = "param_mem"; + }; + + /*after cdsp_secure_heap we add a offset to ignore change address need reconfig*/ + ramoops: ramoops@0xA9800000 { + compatible = "ramoops"; + reg = <0 0xA9800000 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@ac300000 { + reg = <0 0xAC300000 0 0x00B00000>; + label = "mtp_mem"; + }; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <400000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 111 0x00>; + qcom,nq-ven = <&tlmm 83 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_se12_2uart { + compatible = "qcom,msm-geni-console-oem"; +}; +&soc { + oem_serial_pinctrl { + compatible = "oem,oem_serial_pinctrl"; + pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; + pinctrl-0 = <&qupv3_se12_2uart_active>; + pinctrl-1 = <&qupv3_se12_2uart_oem_sleep>; + }; + + oem_aboard_check:oem_aboard_check { + compatible = "oem,aboard"; + interrupt-parent = <&tlmm>; + oem,aboard-gpio-0 = <&tlmm 6 0>; + pinctrl-names = "oem_aboard_active","oem_aboard_sleep"; + pinctrl-0 = <&ab_id0_active>; + pinctrl-1 = <&ab_id0_sleep>; + }; + + oem_rf_cable:oem_rf_cable { + compatible = "oem,rf_cable"; + interrupt-parent = <&tlmm>; + rf,cable-gpio-0 = <&pm8009_gpios 3 0>; + rf,cable-gpio-1 = <&tlmm 175 0>; + rf,cable-gpio-2 = <&pm8009_gpios 4 0>; + rf,cable-gpio-3 = <&tlmm 109 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 &rf_cable_ant9_active >; + }; + +}; +&pm8009_gpios { + pm8009_gpios_pinctl: pm8009_gpios_pinctl { + + rf_cable_ant1_active: rf_cable_ant1_active{ + pins = "gpio3"; + function = "normal"; + power-source = <1>; + bias-pull-up; + qcom,pull-up-strength = <0>; /* 30uA pull up */ + input-enable; /* digital input */ + }; + rf_cable_ant3_active: rf_cable_ant3_active { + pins = "gpio4"; + function = "normal"; + power-source = <1>; + bias-pull-up; + qcom,pull-up-strength = <0>; /* 30uA pull up */ + input-enable; /* digital input */ + }; + + }; +}; + +&tlmm { + ab_id0_active: ab_id0_active { + mux { + pins = "gpio6"; + function = "gpio"; + }; + config { + pins = "gpio6"; + drive-strength = <2>; + bias-pull-up; + }; + }; + ab_id0_sleep: ab_id0_sleep { + mux { + pins = "gpio6"; + function = "gpio"; + }; + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + }; + }; + rf_cable_ant2_active: rf_cable_ant2_active { + mux { + pins = "gpio175"; + function = "gpio"; + }; + config { + pins = "gpio175"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + rf_cable_ant9_active: rf_cable_ant9_active { + mux { + pins = "gpio109"; + function = "gpio"; + }; + config { + pins = "gpio109"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se12_2uart_oem_sleep: qupv3_se12_2uart_oem_sleep { + mux { + pins = "gpio34", "gpio35"; + function = "gpio"; + }; + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&pm8150_gpios { + key_vol_down { + key_vol_down_default: key_vol_down_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <1>; + }; + }; +}; +&soc { + gpio_keys { + pinctrl-0 = <&key_vol_up_default &key_vol_down_default>; + vol_down { + label = "volume_down"; + gpios = <&pm8150_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&qupv3_se11_i2c { + status = "ok"; + aw8697_haptic:aw8697_haptic@5A { + compatible = "awinic,aw8697_haptic"; + reg = <0x5A>; + reset-gpio = <&tlmm 72 0x00>; + irq-gpio = <&tlmm 118 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&aw_irq &aw_reset>; + status = "okay"; + }; +}; + +&tlmm { + aw_irq: aw_irq { + mux { + pins = "gpio118"; + function = "gpio"; + }; + config { + pins = "gpio118"; + drive-strength = <2>; + bias-pull-up; + }; + }; + aw_reset: aw_reset { + mux { + pins = "gpio72"; + function = "gpio"; + }; + config { + pins = "gpio72"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +/* @bsp, 2019/07/08 Battery & Charging porting STRAT */ +&qupv3_se16_i2c { + qcom,clk-freq-out = <100000>; + status = "ok"; + bq27541_battery:bq27541-battery@55 { + status = "ok"; + compatible = "ti,bq27541-battery"; + reg = <0x55>; + qcom,modify-soc-smooth; + op,bat-4p45v; + }; + + oneplus_fastchg@26{ + status = "ok"; + compatible = "microchip,oneplus_fastchg"; + reg = <0x26>; + microchip,mcu-en-gpio = <&tlmm 10 0x00>; + microchip,usb-sw-1-gpio = <&tlmm 50 0x00>; + microchip,usb-sw-2-gpio = <&tlmm 82 0x00>; + microchip,ap-clk = <&tlmm 131 0x00>; + microchip,ap-data = <&tlmm 129 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_read>; + pinctrl-3 =<&ap_data_write>; + op,fw-erase-count = <384>; + op,fw-addr-low = <0x88>; + op,fw-addr-high = <0>; + + op,mcl_verion; + }; +}; + +&pm8150b_gpios { + gpio1_adc { + gpio1_adc_default: gpio1_adc_default { + pins = "gpio1"; /* GPIO 1 */ + function = "normal"; /* normal */ + bias-pull-up; + bias-high-impedance; /* DISABLE GPIO1 for ADC*/ + }; + }; + + gpio8_adc { + gpio8_adc_default: gpio8_adc_default { + pins = "gpio8"; /* GPIO 8 */ + function = "normal"; /* normal */ + bias-pull-up; + bias-high-impedance; /* DISABLE GPIO8 for ADC*/ + }; + }; +}; + +&pm8150b_vadc { + gpio1_v { + reg = ;/* 0x30*/ + label = "gpio1_v"; + qcom,ratiometric; + qcom,hw-settle-time = <800>; + qcom,pre-scaling = <1 1>; + }; + + gpio8_v { + reg = ; + label = "gpio8_v"; + qcom,hw-settle-time = <800>; + qcom,ratiometric; + qcom,pre-scaling = <1 1>; + }; + + chg_therm@4d { + reg = ; + label = "chg_therm"; + qcom,hw-settle-time = <200>; + qcom,ratiometric; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_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 = <1100>; + ibatmax-little-cool-thr-ma = <1900>; + ibatmax-cool-thr-ma = <1100>; + /* 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 = <&pm8150b_pdphy>; + /*ffc temp region*/ + ffc-pre-normal-decidegc = <120>; + ffc-normal-decidegc = <350>; + ffc-warm-decidegc = <400>; + ffc-normal-fcc-ma = <650>; + ffc-warm-fcc-ma = <750>; + ffc-normal-cutoff-ma = <550>; + ffc-warm-cutoff-ma = <650>; + ffc-full-vbat-mv = <4475>; + + /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>; + + /* for external ship mode suppot */ + op,stm-ctrl-gpio = <&tlmm 22 0x00>; + pinctrl-names = "op_ship_mode_default", + "op_usb_temp_adc_default", + "op_usb_temp_adc_sec"; + pinctrl-0 = <&ship_mode_default>; + pinctrl-1 = <&gpio1_adc_default>; + pinctrl-2 = <&gpio8_adc_default>; + + /*usb connector hw auto detection*/ + op,usb-check = <&tlmm 14 0x00>; + /* for usb connector temp protect */ + op,low-voltage-charger; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_V_16>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>, + <&pm8150b_vadc ADC_AMUX_THM4_PU1>, + <&pm8150b_vadc ADC_GPIO4_PU1>, + <&pm8150b_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "mid_voltage", + "usb_in_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp", + "gpio1_voltage", + "gpio8_voltage", + "skin_therm"; + + op,vbus-ctrl-gpio = <&pm8150_gpios 9 GPIO_ACTIVE_LOW>; + + /delete-property/ qcom,fcc-stepping-enable; +}; + +&pm8150b_fg { + qcom,fg-force-load-profile; + oem,use_external_fg; + qcom,fg-rsense-sel = <0>; + qcom,fg-sys-term-current = <180>; + qcom,fg-chg-term-current = <165>; + qcom,fg-esr-calib-dischg; +}; + +&tlmm { + pm8150b_charger { + ship_mode_default: ship_mode_default { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <8>; + bias-pull-down; + }; + }; + }; + + oneplus_fastchg { + usb_sw_active: usb_sw_active { + mux { + pins = "gpio50", "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio50", "gpio82"; + drive-strength = <16>; + bias-pull-down; + }; + }; + + usb_sw_suspend: usb_sw_suspend { + mux { + pins = "gpio50", "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio50", "gpio82"; + drive-strength = <2>; + bias-disable; + }; + }; + + fastchg_active: fastchg_active { + mux { + pins = "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio10"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + fastchg_suspend: fastchg_suspend { + mux { + pins = "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_clk_active: ap_clk_active { + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_clk_suspend: ap_clk_suspend { + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_data_read: ap_data_read { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_data_write: ap_data_write { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; +/* @bsp, 2019/07/08 Battery & Charging porting END */ + +/* @bsp, 2019/08/30 Wireless Charging porting STRAT */ +&soc { + op_wlchg:oneplus_wlchg { + status = "disable"; + compatible = "op,wireless-charger"; + + qcom,usbin_int-gpio = <&pm8150_gpios 1 0x00>; + qcom,wrx_en-gpio = <&pm8150l_gpios 8 0x00>; + qcom,wrx_otg-gpio = <&pm8150l_gpios 11 0x00>; + + pinctrl-names = "wrx_en_active", "wrx_en_sleep", "wrx_en_default", + "wrx_otg_active", "wrx_otg_sleep", + "usbin_int_active", "usbin_int_sleep", "usbin_int_default"; + + pinctrl-0 = <&wrx_en_active>; + pinctrl-1 = <&wrx_en_sleep>; + pinctrl-2 = <&wrx_en_default>; + pinctrl-3 = <&wrx_otg_active>; + pinctrl-4 = <&wrx_otg_sleep>; + pinctrl-5 = <&usbin_int_active>; + pinctrl-6 = <&usbin_int_sleep>; + pinctrl-7 = <&usbin_int_default>; + }; +}; + +&qupv3_se5_i2c { + status = "ok"; + qcom,clk-freq-out = <400000>; + + op_wlchg_rx:op,wlchg_rx@3b { + status = "disable"; + compatible = "op,wlchg-rx-chip"; + reg = <0x3b>; + #address-cells = <1>; + #size-cells = <0>; + + idt_p9415:idt,p9415 { + compatible = "op,p9415-charger"; + qcom,idt_int-gpio = <&tlmm 162 0x00>; + qcom,idt_connect-gpio = <&tlmm 84 0x00>; + qcom,vbat_en-gpio = <&tlmm 117 0x00>; + qcom,idt_en-gpio = <&pm8150_gpios 10 0x00>; + + pinctrl-names = "idt_int_active", "idt_int_sleep", "idt_int_default", + "idt_connect_active", "idt_connect_sleep", "idt_connect_default", + "vbat_en_active", "vbat_en_sleep", "vbat_en_default", + "idt_en_active", "idt_en_sleep", "idt_en_default"; + + pinctrl-0 = <&idt_int_active>; + pinctrl-1 = <&idt_int_sleep>; + pinctrl-2 = <&idt_int_default>; + pinctrl-3 = <&idt_connect_active>; + pinctrl-4 = <&idt_connect_sleep>; + pinctrl-5 = <&idt_connect_default>; + pinctrl-6 = <&vbat_en_active>; + pinctrl-7 = <&vbat_en_sleep>; + pinctrl-8 = <&vbat_en_default>; + pinctrl-9 = <&idt_en_active>; + pinctrl-10 = <&idt_en_sleep>; + pinctrl-11 = <&idt_en_default>; + }; + }; + + // ha7223 + op_wlchg_cp1:chgpump-charger@19 { + status = "disable"; + compatible = "op,chgpump-charger"; + reg = <0x19>; + qcom,cp_en-gpio = <&tlmm 114 0x00>; + pinctrl-names = "cp_en_active", "cp_en_sleep", "cp_en_default"; + pinctrl-0 = <&cp_en_active>; + pinctrl-1 = <&cp_en_sleep>; + pinctrl-2 = <&cp_en_default>; + }; + // bq25970 + op_wlchg_cp2:chgpump-bq25970@66 { + status = "disable"; + compatible = "ti,bq2597x-standalone"; + reg = <0x66>; + qcom,bq_int-gpio = <&tlmm 15 0x00>; + ti,bq2597x,bus-ocp-alarm-disable; + ti,bq2597x,bus-ovp-alarm-disable; + ti,bq2597x,bat-therm-disable; + ti,bq2597x,bus-therm-disable; + ti,bq2597x,die-therm-disable; + ti,bq2597x,bat-ovp-threshold = <4800>; + ti,bq2597x,bat-ovp-alarm-threshold = <4680>; + ti,bq2597x,bat-ocp-threshold = <8100>; + ti,bq2597x,bat-ocp-alarm-threshold = <6500>; + ti,bq2597x,bus-ovp-threshold = <12000>; + ti,bq2597x,bus-ovp-alarm-threshold = <0x00>; + ti,bq2597x,bus-ocp-threshold = <4250>; + ti,bq2597x,bus-ocp-alarm-threshold = <0x00>; + ti,bq2597x,bat-ucp-alarm-threshold = <2000>; + ti,bq2597x,bat-therm-threshold = <0x00>; + ti,bq2597x,bus-therm-threshold = <0x00>; + ti,bq2597x,die-therm-threshold = <0x00>; + ti,bq2597x,ac-ovp-threshold = <0x00>; + ti,bq2597x,sense-resistor-mohm = <0x00>; + pinctrl-names = "bq_irq_active", "bq_irq_default"; + pinctrl-0 = <&bq_irq_active>; + pinctrl-1 = <&bq_irq_default>; + }; +}; + +&tlmm { + op_wlchg_gpio:oneplus_wlchg { + status = "disable"; + cp_en_active: cp_en_active { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + drive-strength = <2>; + bias-disable; + }; + }; + + cp_en_sleep: cp_en_sleep { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + drive-strength = <2>; + bias-disable; + }; + }; + + cp_en_default: cp_en_default { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + drive-strength = <2>; + bias-disable; + }; + }; + + idt_int_active: idt_int_active { + mux { + pins = "gpio162"; + function = "gpio"; + }; + + config { + pins = "gpio162"; + drive-strength = <2>; + input-enable; + /*bias-pull-up; PULL UP*/ + bias-disable; + }; + }; + + idt_int_sleep: idt_int_sleep { + mux { + pins = "gpio162"; + function = "gpio"; + }; + + config { + pins = "gpio162"; + drive-strength = <2>; + bias-disable; + }; + }; + + idt_int_default: idt_int_default { + mux { + pins = "gpio162"; + function = "gpio"; + }; + + config { + pins = "gpio162"; + drive-strength = <2>; + bias-disable; + }; + }; + + idt_connect_active: idt_connect_active { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-disable; + input-enable; + /*bias-pull-up; PULL UP*/ + }; + }; + + idt_connect_sleep: idt_connect_sleep { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-disable; + }; + }; + + idt_connect_default: idt_connect_default { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-disable; + }; + }; + + vbat_en_active: vbat_en_active { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + vbat_en_sleep: vbat_en_sleep { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + vbat_en_default: vbat_en_default { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + bq_irq_active: bq_irq_active { + mux { + pins = "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; + input-enable; + bias-pull-up; /*PULL UP*/ + /*bias-disable;*/ + }; + }; + + bq_irq_default: bq_irq_default { + mux { + pins = "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + + vbus_gpio_default: vbus_gpio_default { + mux { + pins = "gpio172"; + function = "gpio"; + }; + + config { + pins = "gpio172"; + bias-disable; + drive-strength = <2>; + output-low; + }; + }; + }; +}; + +&pm8150_gpios { + op_wlchg_pm8250_gpio:oneplus_wlchg_pm { + status = "disable"; + usbin_int_active: usbin_int_active { + pins = "gpio1"; /* GPIO 1 */ + function = "normal"; /* normal */ + bias-pull-down; //Pull down + power-source = <1>;//VIN1 1.8 + input-enable; + }; + + usbin_int_sleep: usbin_int_sleep { + pins = "gpio1"; /* GPIO 1 */ + function = "normal"; /* normal */ + bias-pull-down; //Pull down + power-source = <1>;//VIN1 1.8 + input-enable; + }; + + usbin_int_default: usbin_int_default { + pins = "gpio1"; /* GPIO 1 */ + function = "normal"; /* normal */ + bias-pull-down; //Pull down + power-source = <1>;//VIN1 1.8 + input-enable; + }; + + idt_en_active: idt_en_active { + pins = "gpio10"; /* GPIO 10 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-high; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + idt_en_sleep: idt_en_sleep { + pins = "gpio10"; /* GPIO 10 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + idt_en_default: idt_en_default { + pins = "gpio10"; /* GPIO 10 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + }; +}; + +&pm8150l_gpios { + op_wlchg_pm8150a_gpio:op_wlchg_pm8150a { + status = "disable"; + otg_en_default: otg_en_default { + pins = "gpio4"; /* GPIO 4 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + drive-push-pull;//CMOS + }; + + wrx_otg_active: wrx_otg_active { + pins = "gpio11"; /* GPIO 11 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-high; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + + wrx_otg_sleep: wrx_otg_sleep { + pins = "gpio11"; /* GPIO 11 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + + wrx_en_active: wrx_en_active { + pins = "gpio8"; /* GPIO 8 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-high; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + + wrx_en_sleep: wrx_en_sleep { + pins = "gpio8"; /* GPIO 8 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + output-low; //digital output, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + wrx_en_default: wrx_en_default { + pins = "gpio8"; /* GPIO 8 */ + function = "normal"; /* normal */ + bias-disable; //No Pull + power-source = <1>;//VIN1 1.8 + input-enable; //digital input, no invert + qcom,drive-strength = <3>; //LOW strength + //drive-push-pull;//CMOS + }; + }; +}; +/* @bsp, 2019/08/30 Wireless Charging porting END */ + +&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; + }; + }; + }; +}; + +&wil6210 { + status = "disabled"; +}; + +&wlan { + qcom,vdd-wlan-rfa1-config = <1900000 2040000 0 0 1>; +}; + +&bluetooth { + qca,bt-vdd-rfa1-voltage-level = <1900000 2040000>; +}; + +/* @bsp, usb config START */ +/* @bsp, As QRD-DVT have this config, keep the same config + * for ldo18 power suspend + */ +&usb_qmp_dp_phy { + vdd-supply = <&pm8150_l18>; + qcom,vdd-voltage-level = <0 912000 912000>; +}; + +&sde_dp { + vdda-0p9-supply = <&pm8150_l18>; + qcom,phy-supply-entries { + qcom,phy-supply-entry@0 { + qcom,supply-min-voltage = <912000>; + qcom,supply-max-voltage = <912000>; + }; + }; +}; +/* @bsp, usb config END */ + +&wdog{ + qcom,bark-time = <15000>; +}; + +&pm8150b_qnovo { + status = "disabled"; +}; + +&wdog{ + qcom,bark-time = <15000>; +}; + +&ufshc_mem { + force-g4; +}; +&sdhc_2 { + status = "disabled"; +}; + 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 000000000000..bda365ffdcfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pcie.dtsi @@ -0,0 +1,814 @@ +#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,target-link-speed = <0x2>; /* limit to gen2 */ + 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 000000000000..cd5e026b810e --- /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"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + 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 = <12>; + 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 000000000000..a5eba34468ee --- /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 000000000000..240b2588cfb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pmic-overlay.dtsi @@ -0,0 +1,195 @@ +#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>; + }; + }; + + 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 000000000000..68b9dca92256 --- /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 000000000000..cc9a4a61ee36 --- /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 000000000000..4e663f5f1e68 --- /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 000000000000..8c1f34eba8be --- /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 000000000000..49936ae5f014 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-regulators.dtsi @@ -0,0 +1,954 @@ +#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 = <1300000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <1300000>; + 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 = <3000000>; + regulator-max-microvolt = <3000000>; + 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 = <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 = <1100000>; + regulator-max-microvolt = <1100000>; + qcom,init-voltage = <1100000>; + 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-ldof4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L4F: pm8009_l4: regulator-pm8009-l4 { + regulator-name = "pm8009_l4"; + 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 000000000000..1c118048c6de --- /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 000000000000..8eb98745d618 --- /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 000000000000..87b03007174c --- /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-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-sde-display.dtsi new file mode 100644 index 000000000000..e1f63197b3f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sde-display.dtsi @@ -0,0 +1,937 @@ +#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-samsung_oneplus_dsc.dtsi" +#include "dsi-panel-nt37800-amoled-dsc-fhd-plus-cmd.dtsi" +#include "dsi-panel-samsung_oneplus_dsc_2nd.dtsi" +#include "dsi-panel-samsung_ana6706_dsc.dtsi" +#include "dsi-panel-samsung_ana6705_fhd_dsc.dtsi" +#include "dsi-panel-samsung_sofef00_m_video.dtsi" +#include "dsi-panel-samsung_dd305_fhd_dsc.dtsi" +#include "dsi-panel-samsung_amb655x_fhd_dsc.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 = "vddi"; + 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 = <2>; + }; + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddr"; + qcom,supply-min-voltage = <1300000>; + qcom,supply-max-voltage = <1300000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-post-off-sleep = <1>; + }; + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "vci"; + 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_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>, + <&clock_rpmh RPMH_LN_BB_CLK2>, + + /* #if defined(CONFIG_PXLW_IRIS5) */ + /*TODO: <&rpmhcc RPMH_LN_BB_CLK2>;*/ + /* #endif */ + <&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", + "pw_bb_clk2", + /* #if defined(CONFIG_PXLW_IRIS5) */ + /*TODO: "ln_bb_clk2"*/ + /* #endif */ + "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>; + + vddi-supply = <&pm8150_l14>; + vddr-supply = <&pm8150a_l2>; + vci-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_samsung_ana6706_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_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_te1_active>; + pinctrl-1 = <&sde_te1_suspend>; + + qcom,platform-te-gpio = <&tlmm 67 0>; + qcom,panel-te-source = <1>; + + vddi-supply = <&pm8150_l14>; + vddr-supply = <&pm8150a_l2>; + vci-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + qcom,dsi-default-panel = <&dsi_samsung_ana6706_dsc_cmd_2nd>; + + 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"; + }; + }; +}; +//#ifdef CONFIG_PXLW_IRIS +#include "pxlw/pxlw-iris5.dtsi" +#include "pxlw/dsi-panel-pxlw.dtsi" +//#endif 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 000000000000..ef3245fa9218 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sde-pll.dtsi @@ -0,0 +1,69 @@ +&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>; + //gdsc-supply = <&mdss_core_gdsc>; + 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>; + //gdsc-supply = <&mdss_core_gdsc>; + 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 000000000000..c280379826df --- /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 000000000000..11b8f950b375 --- /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 000000000000..a375cf719f97 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-thermal-overlay.dtsi @@ -0,0 +1,128 @@ +#include + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&thermal_zones { + soc { + cooling-maps { + soctrip_cpu4 { + trip = <&soc_trip2>; + cooling-device = + <&CPU4 6 6>; + }; + + soctrip_cpu7 { + trip = <&soc_trip2>; + cooling-device = + <&cpu7_isolate 1 1>; + }; + + soctrip_cpu6 { + trip = <&soc_trip>; + cooling-device = + <&cpu6_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 000000000000..499ea86b268d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-thermal.dtsi @@ -0,0 +1,1710 @@ +#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"; + }; +}; + +/{ + 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"; + }; + 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"; + }; + }; + }; + + xo-pmx55-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-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 000000000000..26d3ba6a461a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-usb.dtsi @@ -0,0 +1,598 @@ +#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_BOTH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 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_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,ssp-u3-u0-quirk; + //snps,usb3-u1u2-disable; + usb-core-id = <0>; + tx-fifo-resize; + maximum-speed = "super-speed"; + //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 */ + , + , + ; + + status = "disabled"; + 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 000000000000..06e939b0913a --- /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 000000000000..889d253232bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-gpu.dtsi @@ -0,0 +1,363 @@ +&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>; + }; + }; + }; +}; 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 000000000000..dd76c7741bb4 --- /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 000000000000..792a32b4899e --- /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 000000000000..6581125bf32f --- /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 000000000000..77006e3c06aa --- /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.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion.dts new file mode 100644 index 000000000000..aaf83c850ad7 --- /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 000000000000..94599adb179e --- /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 000000000000..bc5204681693 --- /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 000000000000..965f4023f21d --- /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 000000000000..0e445285402a --- /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 000000000000..d3bf34cf3064 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dtsi @@ -0,0 +1,319 @@ +#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>; + }; + }; +}; + +&power_key { + status = "disabled"; +}; + +&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-ws.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-ws.dts new file mode 100644 index 000000000000..5619b98f13bf --- /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 000000000000..ec73498aab13 --- /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 000000000000..29824a87812d --- /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.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion.dts new file mode 100644 index 000000000000..616943e7a883 --- /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 000000000000..e2b673c42492 --- /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 000000000000..76658bfa29dd --- /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 000000000000..65a8d498dd4f --- /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 000000000000..8ca5010a1ab7 --- /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 000000000000..fc56b3172b42 --- /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 000000000000..a0b09cab7517 --- /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 000000000000..76f19e6aee30 --- /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 000000000000..bc6d7f0d51cc --- /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 000000000000..eba0487d327c --- /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 000000000000..ce4bbf54c171 --- /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 000000000000..589db276254d --- /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.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dts new file mode 100644 index 000000000000..ed5fde6e8c7e --- /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 000000000000..34f3f0bc8279 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dtsi @@ -0,0 +1,1016 @@ +#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"; +}; + +&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"; +}; + +&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>; +}; 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 000000000000..5fbda62473fd --- /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 000000000000..e9651f09bd57 --- /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; + i2c0 = &qupv3_se15_i2c; /* Tfa98xx PA */ + i2c3 = &qupv3_se11_i2c; /* For aw8697*/ + i2c4 = &qupv3_se13_i2c; /* for tp update firmware*/ + }; + + 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 0xAF00000>; + }; + + pil_camera_mem: pil_camera_region@8BF00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8BF00000 0x0 0x500000>; + }; + + pil_wlan_fw_mem: pil_wlan_fw_region@8c400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c400000 0x0 0x100000>; + }; + + pil_ipa_fw_mem: pil_ipa_fw_region@8c500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c500000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: pil_ipa_gsi_region@8c510000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c510000 0x0 0xa000>; + }; + + pil_gpu_mem: pil_gpu_region@8c51a000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c51a000 0x0 0x2000>; + }; + + pil_npu_mem: pil_npu_region@8c600000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c600000 0x0 0x500000>; + }; + + pil_video_mem: pil_video_region@8cb00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8cb00000 0x0 0x500000>; + }; + + pil_cvp_mem: pil_cvp_region@8d000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8d000000 0x0 0x500000>; + }; + + pil_cdsp_mem: pil_cdsp_region@8d500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8d500000 0x0 0x1400000>; + }; + + pil_slpi_mem: pil_slpi_region@8e900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8e900000 0x0 0x1500000>; + }; + + pil_adsp_mem: pil_adsp_region@8fe00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8fe00000 0x0 0x2500000>; + }; + + pil_spss_mem: pil_spss_region@92300000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x92300000 0x0 0x100000>;/* 0x8be00000 -> 0x8c600000*/ + }; + + cdsp_secure_heap: cdsp_secure_heap@92400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x92400000 0x0 0x4600000>;/* 0x8bf00000 -> 0x8c700000*/ + }; + + 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>; + + download_mode@0 { + compatible = "qcom,msm-imem-download_mode"; + reg = <0x658 4>; + }; + + 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@80b00000 { + compatible = "qcom,qseecom"; + reg = <0x80b00000 0x9600000>; + 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,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,secure-domains = <0x0F>; + 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; + cnss-enable-self-recovery; + + 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_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/msm-arm-smmu-bengal.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-bengal.dtsi new file mode 100644 index 000000000000..4e352f8f4bf9 --- /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-kona.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-kona.dtsi new file mode 100644 index 000000000000..5ce2401e0fed --- /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 000000000000..6d7eabccec02 --- /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 000000000000..7b0cc7d30414 --- /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 000000000000..1d4df9efeffe --- /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 000000000000..360e984ab5d5 --- /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-qvr-external.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-qvr-external.dtsi new file mode 100644 index 000000000000..e5056b65ef7e --- /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.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-rdbg.dtsi new file mode 100644 index 000000000000..bb2adf8d0991 --- /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/pm2250-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm2250-rpm-regulator.dtsi new file mode 100644 index 000000000000..ed8a655d621f --- /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 000000000000..ed2c24128583 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm2250.dtsi @@ -0,0 +1,485 @@ +#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>; + }; + }; + + + 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 000000000000..b699d861d455 --- /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 000000000000..a79905c65daa --- /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 000000000000..4cc62d4f4911 --- /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 000000000000..d74f35b4e9d9 --- /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 000000000000..a02607244a5a --- /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/pm660l-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm660l-rpm-regulator.dtsi new file mode 100644 index 000000000000..fcb1d959f2ee --- /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/pm7250b.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm7250b.dtsi new file mode 100644 index 000000000000..c92a2faa9273 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm7250b.dtsi @@ -0,0 +1,639 @@ +#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,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 = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + wake-capable-sensor; + tracks-low; + + trips { + soc_trip:soc-trip { + temperature = <10>; + 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 000000000000..a24c6efae537 --- /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 = <1200000>; + qcom,min-dropout-voltage = <100000>; + qcom,hpm-min-load = <10000>; + }; + + L2P: qcom,pm8008-l2@4100 { + reg = <0x4100>; + regulator-name = "pm8008_l2"; + regulator-min-microvolt = <528000>; + regulator-max-microvolt = <1200000>; + qcom,min-dropout-voltage = <100000>; + 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 000000000000..dd1cea294e04 --- /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 000000000000..9d4e5a4f7ffd --- /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; + + power_key: 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 000000000000..7258fedb9f02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8150b.dtsi @@ -0,0 +1,737 @@ +#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 = <5000>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + tracks-low; + wake-capable-sensor; + + 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/pm8150l.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8150l.dtsi new file mode 100644 index 000000000000..d89288b61785 --- /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 000000000000..26464cc7f5b4 --- /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/pmr735b.dtsi b/arch/arm64/boot/dts/vendor/qcom/pmr735b.dtsi new file mode 100644 index 000000000000..2d085abf6378 --- /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/pxlw/dsi-panel-pxlw.dtsi b/arch/arm64/boot/dts/vendor/qcom/pxlw/dsi-panel-pxlw.dtsi new file mode 100755 index 000000000000..873de77de110 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pxlw/dsi-panel-pxlw.dtsi @@ -0,0 +1,53 @@ +/* Copyright (c) 2020, Pixelworks + * + * 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 "dsi-panel-samsung_ana6706_dsc_2nd.dtsi" + +&dsi_samsung_sofef00_m_video { + pxlw,iris-chip-enable; + pxlw,soft-iris-enable; + qcom,iris-supply-entries = <&dsi_iris_pwr_supply>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0","pw_bb_clk2"; +}; + +&dsi_samsung_ana6706_dsc_cmd { + pxlw,iris-chip-enable; + pxlw,soft-iris-enable; + qcom,iris-supply-entries = <&dsi_iris_pwr_supply>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0","pw_bb_clk2"; +}; + + +&dsi_samsung_ana6706_dsc_cmd_2nd { + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,platform-te-gpio = <&tlmm 67 0>; +}; + +&dsi_samsung_ana6705_dsc_cmd { + pxlw,soft-iris-enable; +}; + +&dsi_samsung_amb655x_dsc_cmd { + pxlw,soft-iris-enable; +}; + +&dsi_samsung_dd305_dsc_cmd { + pxlw,soft-iris-enable; +}; + +&mdss_mdp { + pxlw,dsi-display-primary-active = "qcom,mdss_dsi_samsung_ana6706_dsc_cmd"; + pxlw,dsi-display-secondary-active = "qcom,mdss_dsi_samsung_ana6706_dsc_cmd_2nd"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pxlw/dsi-panel-samsung_ana6706_dsc_2nd.dtsi b/arch/arm64/boot/dts/vendor/qcom/pxlw/dsi-panel-samsung_ana6706_dsc_2nd.dtsi new file mode 100755 index 000000000000..6275beffab04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pxlw/dsi-panel-samsung_ana6706_dsc_2nd.dtsi @@ -0,0 +1,1559 @@ +/* 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_ana6706_dsc_cmd_2nd: qcom,mdss_dsi_samsung_ana6706_dsc_cmd_2nd { + qcom,mdss-dsi-panel-name = "samsung ana6706 dsc cmd mode panel 2nd"; + 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 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <154>; +// qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-resolution-switch-immediate"; + /* 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,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 = <0x9F>; + qcom,mdss-dsi-panel-status-read-length = <1>; + + qcom,mdss-dsi-lp11-init; + qcom,mdss-bl-high2bit; + qcom,mdss-loading-effect; + 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-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-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,mdss-mdp-transfer-time-us = <6130>; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2376>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <48>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <1100>; + qcom,mdss-dsi-v-front-porch = <1100>; + qcom,mdss-dsi-v-pulse-width = <188>; + 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 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 02 /* 60HZ */ + 15 01 00 00 00 00 02 BA 02 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + 39 01 00 00 06 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 02 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 48 + 04 38 00 48 02 1C 02 1C + 02 00 02 52 00 20 06 3B + 00 07 00 0F 01 B1 01 6A + 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 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �?120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 02 /* 60HZ */ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <72>; + 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-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2376>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <48>; + qcom,mdss-dsi-h-pulse-width = <8>; + 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 = <2>; + 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 = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 22 /* 120HZ */ + 15 01 00 00 00 00 02 BA 02 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* for scanline */ + 15 01 00 00 00 00 02 B9 01 + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 05 B9 0C 54 00 0B + 39 01 00 00 07 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 02 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 48 + 04 38 00 48 02 1C 02 1C + 02 00 02 52 00 20 06 3B + 00 07 00 0F 01 B1 01 6A + 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 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 09 47 /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �?120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 22 /* 120HZ */ + 15 01 00 00 00 00 02 F7 0F + /* for scanline */ + 15 01 00 00 00 00 02 B9 01 + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 05 B9 0C 54 00 0B + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <540 540>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <72>; + 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@2 { + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-clockrate = <1452000000>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3168>; + qcom,mdss-dsi-h-front-porch = <88>; + qcom,mdss-dsi-h-back-porch = <56>; + qcom,mdss-dsi-h-pulse-width = <8>; + 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 = <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-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 20 /* 120HZ */ + 15 01 00 00 00 00 02 BA 03 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + 39 01 00 00 07 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 03 + 39 01 00 00 00 00 59 9E + 12 00 00 AB 30 80 0C 60 + 05 A0 00 60 02 D0 02 D0 + 02 00 02 C2 00 20 09 62 + 00 0A 00 0F 01 44 00 CC + 18 00 10 F0 07 10 20 00 + 06 0F 0F 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 02 02 22 00 2A 40 + 2A BE 3A FC 3A FA 3A F8 + 3B 38 3B 78 3B B6 4B B6 + 4B F4 4B F4 6C 34 84 74 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �?120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 20 /* 120HZ */ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 06 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <720 720>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <96>; + 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@3 { + qcom,mdss-mdp-transfer-time-us = <12000>; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <825600000>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <3168>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <80>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <180>; + qcom,mdss-dsi-v-front-porch = <180>; + qcom,mdss-dsi-v-pulse-width = <12>; + 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 F0 5A 5A + 07 01 00 00 00 00 01 01 + 15 01 00 00 00 00 02 60 00 /* 60HZ */ + 15 01 00 00 00 00 02 BA 03 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + 39 01 00 00 08 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* Sleep Out(11h) */ + 05 01 00 00 0B 00 01 11 + /* ELVDD/ELVSS soft-start Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 09 + 15 01 00 00 00 00 02 B5 08 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 22 + 15 01 00 00 00 00 02 F5 65 + 15 01 00 00 00 00 02 B0 38 + 15 01 00 00 00 00 02 F5 0F + 15 01 00 00 00 00 02 B0 56 + 15 01 00 00 00 00 02 F5 C4 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 03 CB FF FF + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 0B 00 03 F0 A5 A5 + /* PPS Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable */ + 15 01 00 00 00 00 02 BA 03 + 39 01 00 00 00 00 59 9E + 11 00 00 AB 30 A0 0C 60 + 05 A0 00 10 02 D0 03 84 + 01 9A 02 68 00 19 01 D1 + 00 0E 00 09 04 CD 05 D6 + 16 00 10 EC 07 10 20 00 + 06 0F 0F 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 02 02 22 00 2A 40 + 32 BE 3A FC 3A FA 3A F8 + 3B 38 3B 78 3B 76 4B B6 + 4B B4 4B F4 5B F4 7C 34 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + /* Common Setting */ + 15 01 00 00 00 00 02 35 00 /* TE On(Vsync) */ + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 05 9F /* CASET */ + 39 01 00 00 00 00 05 2B 00 00 0C 5F /* PASET */ + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 05 B9 07 02 40 23 /* SYNC ENABLE */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* FREQ_MODE Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 0A + 15 01 00 00 00 00 02 FB 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FD(Fast Discharge) Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 54 + 15 01 00 00 00 00 02 B5 48 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dither Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 99 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 11bit Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 5C + 15 01 00 00 00 00 02 B1 03 + 39 01 00 00 6F 00 03 F0 A5 A5 + /* Brightness Control */ + 39 01 00 00 00 00 03 F0 5A 5A /* Dimming Setting */ + 15 01 00 00 00 00 02 B0 0B + 15 01 00 00 00 00 02 B1 01 /* Dimming Speed Setting : 0x01 : 1Frame*/ + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 /* ELVSS DIM OFF */ + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + /* 60hz �?120hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 60 00 /*60HZ*/ + 15 01 00 00 00 00 02 F7 0F + 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 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + /* HBM Mode Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 21 + 39 01 00 00 00 00 0C B5 02 04 05 06 07 08 09 0A 0B 0C 0D + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 /*0x400-0x7ff*/ + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0D 00 03 51 09 CA + /* DLY ON + ELVSS DIM OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 02 + 15 01 00 00 00 00 02 B5 13 + 39 01 00 00 11 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 6E + 39 01 00 00 00 00 04 D3 80 80 80 + 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 07 /* mode 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 + 15 01 00 00 00 00 02 B0 0C + 15 01 00 00 00 00 02 92 27 /* mode ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-1-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 01 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-mca-setting-mode-0-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 06 + 15 01 00 00 00 00 02 97 00 + 15 01 00 00 00 00 02 B0 04 + 15 01 00 00 00 00 02 98 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-0 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 80 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 81 + ]; + qcom,mdss-dsi-panel-seed-lp-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 27 91 + 00 2F FF 0C 1C 00 40 0D + 00 00 0C 1C 5A C6 00 44 + 44 0C 1C 5A C6 00 22 22 + 0C 1C 5A C6 00 11 11 0C + 1C 5A C6 00 00 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 8C 82 + ]; + qcom,mdss-dsi-panel-seed-lp-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 91 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + 15 01 00 00 00 00 02 82 80 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B8 99 10 05 36 BF 15 0C 00 A5 4C DC CC B7 14 B4 D9 DB 1C FF FF FF + 15 01 00 00 00 00 02 B8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-register-read-command = [ + 06 01 00 00 00 00 01 DA + ]; + qcom,mdss-dsi-panel-gamma-change-write-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 AA + 39 01 00 00 00 00 0D C7 2B 14 C1 2C 0F AE 10 FB 01 9A 97 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 A7 + 39 01 00 00 00 00 0D C9 01 04 3D AE 01 36 00 A5 01 14 16 00 + 15 01 00 00 00 00 02 F7 0F + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 1A + 39 01 00 00 00 00 0D C9 C5 44 D8 14 B1 CA 10 04 4D 4D 9C 40 + 15 01 00 00 00 00 02 F7 0F + 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_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-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-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-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-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-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-mca-setting-mode-0-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-0-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-seed-lp-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-register-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-gamma-change-write-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,lm-split = <720 720>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-encoders = <2>; + 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; + }; + }; + }; +}; + +&dsi_samsung_ana6706_dsc_cmd_2nd { + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-brightness-default-val = <360>; + qcom,mdss-brightness-max-level = <2047>; +}; + +&soc { + dsi_samsung_ana6706_dsc_cmd_2nd { + qcom,dsi-display-active; + }; +}; + +&dsi_samsung_ana6706_dsc_cmd_2nd { + //qcom,ulps-enabled; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { /* FHD+ 60hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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 = <0>; + }; + timing@1 { /* FHD+ 120hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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 = <0>; + }; + timing@2 { /* WQHD+ 120hz 726Mhz 1452Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 2F 0C 0C 2A 27 0C 0D 09 02 04 00 26 1B]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <0>; + }; + timing@3 { /* WQHD+ 60hz 412.8Mhz 825.6Mbps */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 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 = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5-cfg-samsung-wqhd-dsc8-90fps-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5-cfg-samsung-wqhd-dsc8-90fps-cmd.dtsi new file mode 100755 index 000000000000..240ccbb71968 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5-cfg-samsung-wqhd-dsc8-90fps-cmd.dtsi @@ -0,0 +1,3577 @@ +/*Fullchip dtype, last, wait, ip, opt, dlen sys*/ +&vendor { +pxlw { + mdss_iris_cfg_samsung_oneplus_dsc8_90fps_cmd: pxlw,mdss_iris_cfg_samsung_oneplus_dsc8_90fps_cmd { + +pxlw,panel-type = "PANEL_OLED"; +/*low power control: dynamic power gating, ulps low power, analog bypass */ +pxlw,low-power = [00 01 01]; +pxlw,chip-ver = <0x6935>; +pxlw,pkt-payload-size = <228>; +pxlw,last-for-per-pkt = <2>; +pxlw,pt-last-for-per-pkt = <0>; +pxlw,min-color-temp = <2500>; +pxlw,max-color-temp = <10000>; +/* 0: DSI_VIDEO_MODE, 1: DSI_CMD_MODE */ +pxlw,iris-tx-mode = /bits/ 8 <1>; +pxlw,panel-dimming-brightness = <4095>; +//pxlw,panel-hbm = [28 e8]; +pxlw,panel-te = <60>; +pxlw,ap-te = <60>; +pxlw,loop-back-mode = <0>; +pxlw,loop-back-mode-res = <255>; + +pxlw,iris-lightup-sequence-pre0 = [ + /*sys*/ + 00 a0 00 + 00 00 00 +]; + + +pxlw,iris-lightup-sequence-pre1 = [ + /*sys*/ + 00 a0 00 + 00 00 00 +]; +pxlw,iris-lightup-sequence-cont-splash = [ + + /* rx ctrl */ + 01 f0 00 + /* tx */ + 02 01 00 + 02 00 00 + /* dtg */ + 05 00 00 + 05 f0 00 + /*dport*/ + 04 f0 00 + 04 80 00 + + /*pwil*/ + 03 00 00 + 03 01 00 + 03 02 00 + 03 03 00 + 03 04 00 + 03 80 00 + + 23 00 00 + 23 80 00 + + /* dsc decoder */ + 07 fa 01 + 07 8a 01 + /* dsc encoder */ + 08 fa 01 + 08 8a 00 +]; +pxlw,iris-lightup-sequence = [ + /* rx ctrl */ + 01 f0 01 + /*rx author*/ + 21 f1 01 + 21 f0 01 + /*tx*/ + 02 01 01 + 02 00 00 + /*dtg*/ + 05 00 00 + 05 f0 00 + /* blc_pwm */ + 06 f0 01 + 06 00 01 + /* hdr init */ + 09 70 01 + /*lut*/ + 80 00 01 + 80 01 01 + 80 f1 00 + 81 00 01 + 81 01 01 + 81 02 01 + 86 00 00 + 83 00 01 + 8a 00 01 + 89 00 00 + 82 04 01 + 82 14 01 + 82 24 01 + 82 34 01 + 82 44 01 + 82 54 01 + 82 64 01 + 82 74 00 + 82 84 00 + 84 00 01 + 85 00 01 + /*DMA */ + 11 f1 01 + /*dport*/ + 04 f0 01 + 04 80 01 + /*pwil*/ + 03 f0 01 + 03 f1 01 + 03 f2 01 + 03 f3 01 + 03 f4 01 + 03 20 01 + 03 a0 01 + 03 b0 01 + 03 c0 01 + 03 d0 01 + 03 40 01 + 03 80 01 + /*pwil_v6*/ + 23 f0 01 + /*blending*/ + 2e f0 01 + /*peaking*/ + 0c f0 01 + 0c a0 01 + 0c 80 01 + /*dpp*/ + 0e f0 01 + 0e f1 01 + 0e a0 01 + 0e 80 01 + /*hdr*/ + 09 a0 01 + 09 80 01 + /*cm*/ + 0a f0 01 + 0a a0 01 + 0a 80 01 + 0a 20 01 + /*lce*/ + 0d f0 01 + 0d a0 01 + 0d 80 01 + 0d 70 01 + 0d 71 01 + /* scaler1d */ + 0b f0 01 + 0b a0 01 + /* scaler1d pp */ + 2f f0 01 + /* dbc */ + 0f f0 01 + 0f a0 01 + 0f 70 01 + /*psr mif*/ + 2d f0 01 + /* dsc decoder */ + 07 f0 00 + 07 a0 00 + 07 80 00 + /*dsc aux*/ + 37 f0 00 + /* dsc encoder */ + 08 f0 00 + /* dsc decoder 2 */ + 25 f0 01 + 25 f1 01 + /* dsc encoder 2 */ + 24 f0 01 + 24 f1 01 + /* osd_comp */ + 2a f0 01 + 2b f0 01 + /* pq configure */ + /* peaking */ + 0c 00 01 + 0c 11 01 + /* cm */ + 0a 00 01 + 0a 10 01 + 0a b0 01 + 0a b1 01 + 0a b2 01 + 0a b3 01 + 0a b4 01 + 0a b5 01 + 0a 40 01 + /* lce */ + 0d 00 01 + 0d 10 01 + 0d fd 01 + /* dbc */ + 0f 00 01 + 0f fc 01 + /* dpp */ + 0e 00 01 + 0e fd 01 + 0e fc 01 + 0e 40 01 + 0e 50 01 + 0e 61 01 + 0e 70 01 + /* pwil */ + 03 61 01 + 03 95 01 + 03 51 01 + 03 23 01 + /*hdr*/ + 09 00 01 + 09 93 01 + /*DMA*/ + 11 e1 00 + /* video abyp*/ + 01 e0 00 + /* manual power */ + 00 f0 00 +]; + +//for 60fps switch +pxlw,iris-timing-switch-sequence = [ + /*disable mipi*/ + 02 02 01 + + /* rx ctrl */ + 01 f0 01 + /*tx*/ + 02 01 01 + 02 00 01 + /*dtg*/ + 05 00 00 + 05 f0 00 + /*DMA */ + 11 f1 01 + /*dport*/ + 04 f0 01 + 04 80 01 + /*pwil*/ + 03 f0 01 + 03 f1 01 + 03 f2 01 + 03 f3 01 + 03 f4 01 + 03 20 01 + 03 a0 01 + 03 b0 01 + 03 c0 01 + 03 d0 01 + 03 40 01 + 03 80 01 + /*blending*/ + 2e f0 01 + /*dpp*/ + 0e a0 01 + 0e 01 01 + /*lce*/ + 0d f0 01 + /* scaler1d */ + 0b f0 01 + 0b a0 01 + /* scaler1d pp */ + 2f f0 01 + /*psr mif*/ + 2d f0 01 + /* dsc decoder */ + 07 f0 01 + 07 a0 01 + 07 80 01 + /* dsc encoder */ + 08 f0 01 + /* pwil */ + 03 61 01 + 03 95 01 + 03 51 01 + 03 23 01 + /*rx aux */ + 21 f2 01 + 21 f0 01 + /*dsc aux*/ + 37 f0 00 + /* osd_comp */ + 2a f0 01 + 2b f0 01 + /*pwil_v6*/ + 23 f0 01 + /* mipi abyp*/ + 01 e0 01 + /*DMA*/ + 11 e1 00 + + /*enable mipi*/ + 02 03 00 +]; + +//for 120fps switch +pxlw,iris-timing-switch-sequence-1 = [ + /*disable mipi*/ + 02 02 01 + + /* rx ctrl */ + 01 f0 01 + /*tx*/ + 02 02 01 + 02 00 01 + /*dtg*/ + 05 01 00 + 05 f0 00 + /*DMA */ + 11 f1 01 + /*dport*/ + 04 f0 01 + 04 80 01 + /*pwil*/ + 03 f0 01 + 03 f1 01 + 03 f2 01 + 03 f3 01 + 03 f4 01 + 03 20 01 + 03 a0 01 + 03 b0 01 + 03 c0 01 + 03 d0 01 + 03 40 01 + 03 80 01 + /*blending*/ + 2e f1 01 + /*dpp*/ + 0e a0 01 + 0e 01 01 + /*lce*/ + 0d f0 01 + /* scaler1d */ + 0b f0 01 + 0b a0 01 + /* scaler1d pp */ + 2f f0 01 + /*psr mif*/ + 2d f0 01 + /* dsc decoder */ + 07 f0 01 + 07 a0 01 + 07 80 01 + /* dsc encoder */ + 08 f0 01 + /* pwil */ + 03 61 01 + 03 95 01 + 03 51 01 + 03 23 01 + /*rx aux */ + 21 f2 01 + 21 f0 01 + /*dsc aux*/ + 37 f0 00 + /* osd_comp */ + 2a f0 01 + 2b f0 01 + /*pwil_v6*/ + 23 f0 01 + /* mipi abyp*/ + 01 e1 01 + /*DMA*/ + 11 e1 00 + + /*enable mipi*/ + 02 03 00 +]; + + +pxlw,iris-pq-default-val = [ + /* sys */ + 00 a0 + /* rx */ + 01 e0 + /* tx */ + 02 00 + /* peaking */ + 0c 00 + 0c 11 + /* cm */ + 0a 00 + 0a 10 + 0a b0 + 0a b1 + 0a b2 + 0a b3 + 0a b4 + 0a b5 + 0a 40 + 0a 20 + /* lce */ + 0d 00 + 0d 10 + 0d fd + 0d a0 + /* dbc */ + 0f 00 + 0f fc + /* dpp */ + 0e 00 + 0e 40 + 0e fc + 0e fd + 0e 50 + 0e 60 + 0e 70 + /* pwil */ + 03 f1 + 03 f2 + 03 f4 + 03 23 + 03 a0 + 03 b0 + 03 c0 + 03 d0 + 03 40 + 03 80 + 03 61 + 03 95 + 03 51 + /*hdr*/ + 09 00 + 09 93 + /*blc_pwm*/ + 06 00 + /* lut */ + 80 00 + 80 01 + 80 f1 + 81 00 + 81 01 + 81 02 + 86 00 + 83 00 + 8a 00 + 89 00 + 82 04 + 82 14 + 82 24 + 82 34 + 82 44 + 82 54 + 82 64 + 82 74 + 82 84 + 84 00 + 85 00 + /*DMA */ + 11 f1 + /*MIPI_TX*/ + 02 e0 + /*DTG*/ + 05 00 + 05 f0 + /*DPORT*/ + 04 f0 + 04 80 +]; + + // for 1440x3168@60fps + pxlw,iris-cmd-list = + < + // build : 02-06-2020 19:24 + // workbook: v0.69.1.u + // panel : v0p69p1pu_oneplus_wqhd_dsc10_1440x3168_60fps_bpc10_bpp10_336p0_0206 + + // mipi_rx: dphy + 0x29 0x01 0x00 0x01 0x01F1 0x11 0xFFFFFFF4 + 0xF1800808 0x0D020200 0xF1800818 0x00000005 0xF1800A00 0x00004960 + 0xF1800A08 0x00000307 0xF1800A14 0x00000307 0xF1800A1C 0x00000307 + 0xF1800A24 0x00000307 0xF1800A2C 0x00000304 + + // mipi_rx: dphy 2nd timing + 0x29 0x01 0x00 0x01 0x01F2 0x11 0xFFFFFFF4 + 0xF1800808 0x0D020200 0xF1800818 0x00000005 0xF1800A00 0x00004960 + 0xF1800A08 0x00000307 0xF1800A14 0x00000307 0xF1800A1C 0x00000307 + 0xF1800A24 0x00000307 0xF1800A2C 0x00000304 + + // mipi_rx: ctrl + 0x29 0x01 0x00 0x01 0x00F0 0x13 0xFFFFFFF4 + 0xF1800238 0x00770000 0xF1800300 0x059F0000 0xF1800304 0x0C5F0000 + 0xF1801804 0x00000780 0xF1800104 0x01000000 0xF1800144 0x001002D0 + 0xF1800148 0x00000384 0xF1800080 0x00000110 0xF180001C 0x00000000 + + // mipi_rx: enter TTL bypass + 0x29 0x01 0x00 0x01 0x00D0 0x03 0xFFFFFFF4 + 0xF1800010 0x00200317 + + // mipi_rx: exit TTL bypass + 0x29 0x01 0x00 0x01 0x00D1 0x03 0xFFFFFFF4 + 0xF1800010 0x00200217 + + // mipi: abyp + 0x29 0x00 0x00 0x01 0x00E0 0x23 0x0001000C 0xF1311E38 + 0x0D020200 0x00000005 0x00004960 0x00000307 0x00770000 0x059F0000 + 0x0C5F0000 0x00000780 0x01000000 0x001002D0 0x00000384 0x00000110 + 0x00004960 0x00410304 0x0000027F 0x3A040006 0x23082208 0x23081D07 + 0x00000201 0x034E0100 0x0068FB00 0x00FFFFFF 0x0A8C0780 0x00CB40C4 + 0x00000020 0x001002D0 0x00000384 0x059F0000 0x0C5F0000 0x000000F1 + 0x02B10708 0xC201C139 0x00200217 + + // mipi: abyp + 0x29 0x01 0x00 0x01 0x00E0 0x07 0x0001000C 0xF1311FC4 + 0x00000307 0x00000307 0x00000307 0x00000304 0x00000000 + + // mipi: abyp 2nd timing + 0x29 0x00 0x00 0x01 0x00E1 0x23 0x0001000C 0xF1311E38 + 0x0D020200 0x00000005 0x00004960 0x00000307 0x00770000 0x059F0000 + 0x0C5F0000 0x00000780 0x01000000 0x001002D0 0x00000384 0x00000110 + 0x00004960 0x00410304 0x0000027F 0x3A040006 0x23082208 0x23081D07 + 0x00000201 0x034E0100 0x0068FB00 0x00FFFFFF 0x0A8C0780 0x00CB40C4 + 0x00000020 0x001002D0 0x00000384 0x059F0000 0x0C5F0000 0x000000F1 + 0x02B10708 0xC201C139 0x00200217 + + // mipi: abyp 2nd timing + 0x29 0x01 0x00 0x01 0x00E1 0x07 0x0001000C 0xF1311FC4 + 0x00000307 0x00000307 0x00000307 0x00000304 0x00000000 + + // sys: a0: init 0 + 0x29 0x01 0x64 0x00 0x00A0 0x15 0xFFFFFFF4 + 0xF0000004 0x002280A2 0xF0000008 0x0010F008 0xF0000020 0x002A80AA + 0xF0000024 0x0000F010 0xF0000000 0x00000051 0xF0000000 0x00000052 + 0xF0000000 0x00000050 0xF000001C 0x00000081 0xF000001C 0x00000082 + 0xF000001C 0x00000080 + + // sys: a1: init 0 2nd timing + 0x29 0x01 0x64 0x00 0x00A1 0x15 0xFFFFFFF4 + 0xF0000004 0x002280A2 0xF0000008 0x0010F008 0xF0000020 0x002A80AA + 0xF0000024 0x0000F010 0xF0000000 0x00000051 0xF0000000 0x00000052 + 0xF0000000 0x00000050 0xF000001C 0x00000081 0xF000001C 0x00000082 + 0xF000001C 0x00000080 + + // sys: misc + 0x29 0x01 0x00 0x00 0x0000 0x15 0xFFFFFFF4 + 0xF000004C 0x0E109C20 0xF0000048 0x000032A0 0xF00000E0 0x00008180 + 0xF00000E4 0x0000D400 0xF0000060 0x0F1BC3C6 0xF00000C0 0x000001D5 + 0xF00000C4 0x000009EF 0xF0000088 0x0000001D 0xF00000F4 0x00000640 + 0xF00000D4 0x3F420303 + + // sys: abyp: enter + 0x29 0x01 0x00 0x00 0x0104 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000002 0xF00000EC 0x00000000 + + // sys: abyp: exit + 0x29 0x01 0x00 0x00 0x0105 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000001 0xF00000EC 0x00000000 + + // sys: pad select bitmask + 0x29 0x01 0x00 0x00 0x0006 0x03 0xFFFFFFF4 + 0xF00000E8 0x00000000 + + // sys: mem repair bitmask + 0x29 0x01 0x00 0x00 0x0007 0x03 0xFFFFFFF4 + 0xF00000F4 0x00000640 + + // sys: abyp: hs mode enter + 0x29 0x01 0x00 0x00 0x0008 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000002 0xF00000EC 0x00000000 + + // sys: efuse for video abyp + 0x29 0x01 0x00 0x00 0x0010 0x05 0xFFFFFFF4 + 0xF0010004 0x03F000C0 0xF0010008 0x80000000 + + // sys: ungate clocks, power on PLLs + 0x29 0x01 0x00 0x00 0x0120 0x09 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000000 0x00000050 + 0xF000001C 0x00000080 + + // sys: switch clock mux back, power up domains + 0x29 0x01 0x00 0x00 0x0121 0x05 0xFFFFFFF4 + 0xF0000048 0x000032A0 0xF0000060 0x0F1BC3C6 + + // sys: power off domains, switch clock mux to XCLK + 0x29 0x01 0x00 0x00 0x0122 0x05 0xFFFFFFF4 + 0xF0000060 0x0F1BC006 0xF0000048 0x00002000 + + // sys: power off PLLs, gate clocks + 0x29 0x01 0x00 0x00 0x0123 0x09 0xFFFFFFF4 + 0xF000001C 0x00000084 0xF0000000 0x00000054 0xF0000050 0x0000CC26 + 0xF0000054 0x7A544004 + + // sys: ungate clocks, power on MIPI PLL + 0x29 0x01 0x00 0x00 0x0124 0x07 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF000001C 0x00000080 + + // sys: switch clock mux default + 0x29 0x01 0x00 0x00 0x0125 0x03 0xFFFFFFF4 + 0xF0000048 0x00004F60 + + // sys: switch clock mux to XCLK, power off MIPI PLL, gate clocks + 0x29 0x01 0x00 0x00 0x0126 0x09 0xFFFFFFF4 + 0xF0000048 0x00004000 0xF000001C 0x00000084 0xF0000050 0x0000CC26 + 0xF0000054 0x7A544004 + + // sys: ungate clocks, program PLLs + 0x29 0x01 0x64 0x00 0x0127 0x19 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000004 0x002280A2 + 0xF0000008 0x0010F008 0xF0000020 0x002A80AA 0xF0000024 0x0000F010 + 0xF0000000 0x00000051 0xF0000000 0x00000052 0xF0000000 0x00000050 + 0xF000001C 0x00000081 0xF000001C 0x00000082 0xF000001C 0x00000080 + + // sys: ungate clocks, program PLLs 2nd timing + 0x29 0x01 0x64 0x00 0x0128 0x19 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000004 0x002280A2 + 0xF0000008 0x0010F008 0xF0000020 0x002A80AA 0xF0000024 0x0000F010 + 0xF0000000 0x00000051 0xF0000000 0x00000052 0xF0000000 0x00000050 + 0xF000001C 0x00000081 0xF000001C 0x00000082 0xF000001C 0x00000080 + + // dtg: init + 0x29 0x01 0x00 0x05 0x0000 0x030 0x00000000 0xF1200000 + 0x00000003 0x00000003 0x000001C2 0x00000003 0x00000014 0x000001A5 + 0x00000C60 0x00000078 0xA0914A53 0x80000E64 0x80000E64 0x00000008 + 0x00000E15 0x00000000 0x00000000 0x00000000 0x00000E02 0x0019AF2A + 0x00000000 0x00001DC6 0x00001DC6 0x000001CB 0x00000000 0x001A3EC0 + 0x00000000 0x00000000 0x00000000 0x00000000 0x10000101 0x00010001 + 0x80000E64 0x00198B3B 0x00198B3B 0x000001CB 0x00000000 0x00000000 + 0x001A3EC0 0x001A1D4F 0x00000000 0x00000009 0x000001C1 0x00000101 + 0x0025C3F8 0x00000000 0x00000000 0x00000005 + + // dtg: init 2nd timing + 0x29 0x01 0x00 0x05 0x0001 0x30 0x00000000 0xF1200000 + 0x00000003 0x00000003 0x000001C2 0x00000003 0x00000014 0x000001A5 + 0x00000C60 0x00000078 0xA0914A53 0x80000E64 0x80000E64 0x00000008 + 0x00000E15 0x00000000 0x00000000 0x00000000 0x00000E02 0x0019AF2A + 0x00000000 0x00001DC6 0x00001DC6 0x000001CB 0x00000000 0x001A3EC0 + 0x00000000 0x00000000 0x00000000 0x00000000 0x10000101 0x00010001 + 0x80000E64 0x00198B3B 0x00198B3B 0x000001CB 0x00000000 0x00000000 + 0x001A3EC0 0x0019AF2A 0x00000000 0x00000009 0x000001C1 0x00000101 + 0x0025C3F8 0x00000000 0x00000000 0x00000005 + + // dtg: update + 0x29 0x01 0x00 0x05 0x00F0 0x03 0xFFFFFFF4 + 0xF1210000 0x0000000F + + // mipi_tx: init + 0x29 0x01 0x00 0x02 0x0000 0x23 0xFFFFFFF4 + 0xF1880050 0x3A040006 0xF1880054 0x23082208 0xF1880058 0x23081D07 + 0xF1880004 0x00000201 0xF1880020 0x034E0100 0xF188002C 0x0068FB00 + 0xF1880030 0x00FFFFFF 0xF1880034 0x0A8C0780 0xF1880038 0x00CB40C4 + 0xF1880044 0x00000020 0xF1880010 0x001002D0 0xF1880014 0x00000384 + 0xF1880018 0x059F0000 0xF188001C 0x0C5F0000 0xF1880008 0x000000F1 + 0xF188000C 0x02B10708 0xF1880000 0xC201C139 + + // mipi_tx: init 2nd timing + 0x29 0x01 0x00 0x02 0x0004 0x23 0xFFFFFFF4 + 0xF1880050 0x3A040006 0xF1880054 0x23082208 0xF1880058 0x23081D07 + 0xF1880004 0x00000201 0xF1880020 0x034E0100 0xF188002C 0x0068FB00 + 0xF1880030 0x00FFFFFF 0xF1880034 0x0A8C0780 0xF1880038 0x00CB40C4 + 0xF1880044 0x00000020 0xF1880010 0x001002D0 0xF1880014 0x00000384 + 0xF1880018 0x059F0000 0xF188001C 0x0C5F0000 0xF1880008 0x000000F1 + 0xF188000C 0x02B10708 0xF1880000 0xC201C139 + + // mipi_tx: dphy + 0x29 0x01 0x00 0x02 0x0001 0x07 0xFFFFFFF4 + 0xF18C0200 0x00004960 0xF18C0004 0x00410304 0xF18C0210 0x0000027F + + // mipi_tx: mode switch s3 + 0x29 0x01 0x00 0x02 0x0002 0x03 0xFFFFFFF4 + 0xF1880008 0x00000081 + + // mipi_tx: mode switch s5 + 0x29 0x01 0x00 0x02 0x0003 0x03 0xFFFFFFF4 + 0xF1880008 0x000000F1 + + // dport: init + 0x29 0x01 0x00 0x04 0x00F0 0x009 0x0001000C 0xF1311578 + 0xE0008007 0x21000803 0x4C6001C2 0x46000800 0x06081814 0x00044100 + 0x00000000 + + // dport: update + 0x29 0x01 0x00 0x04 0x0080 0x003 0x0001000C 0xF1311594 + 0x00000001 + + // hdr: 0 + 0x29 0x01 0x00 0x09 0x0000 0x5E 0x0001000C 0xF1310FD8 + 0x0000016D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x05A00C60 0x0000003A 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7E29 0x7FD77E8F 0x02000079 0x021A0200 0x00007F71 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x1D0E3617 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01100001 + + // hdr: 2 + 0x29 0x01 0x00 0x09 0x0002 0x5E 0x0001000C 0xF1310FD8 + 0x0000006D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x05A00C60 0x0000003A 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x1D0E3617 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01100001 + + // hdr: 5 + 0x29 0x01 0x00 0x09 0x0005 0x5E 0x0001000C 0xF1310FD8 + 0x00001028 0x0FFF0000 0x0FFF0000 0x058F0124 0x00000804 0x0AE0023C + 0x00000FAD 0x00000011 0x0FFF082E 0x026600CC 0x002800CC 0x10080C06 + 0x20CC0F33 0x000AFFFF 0x00006461 0x00006461 0x00A30064 0x00A30064 + 0x05A00C60 0x0000003A 0x0000020B 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x01790087 0x00120024 + 0x016F0005 0x001C0101 0x00000007 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0020E04A 0x003C9FC4 0x0017AF51 0x00408040 0x00000000 0x00000000 + 0x1C1C044E 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x0003FFFF 0x0003FFFF 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01400001 + + // hdr: 9 + 0x29 0x01 0x00 0x09 0x0009 0x5E 0x0001000C 0xF1310FD8 + 0x0000006D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x05A00C60 0x0000003A 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000004 0x08000800 0x00000800 + 0x0F0D7EAF 0x7B6E0BCC 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000008 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00040000 0x00000000 0x00040000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x110A3617 0x00140000 0x0007FFFF 0x00140001 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x07940708 + 0x00000000 0x01100001 + + // hdr: c + 0x29 0x01 0x00 0x09 0x000C 0x5E 0x0001000C 0xF1310FD8 + 0x00001028 0x0FFF0000 0x0FFF0000 0x058F0124 0x00000804 0x0AE0023C + 0x00000FAD 0x00000011 0x0FFF082E 0x026600CC 0x002800CC 0x10080C06 + 0x20CC0F33 0x000AFFFF 0x00006461 0x00006461 0x00A30064 0x00A30064 + 0x05A00C60 0x0000003A 0x0000020B 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x01790087 0x00120024 + 0x016F0005 0x001C0101 0x00000007 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000004 0x08000800 0x00000800 + 0x0E2D7D3F 0x7A490B37 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000008 0x04B27CA7 0x7F597D5A 0x040000E9 0x02640400 0x00007EA6 + 0x00040000 0x00000000 0x00040000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0020E04A 0x003C9FC4 0x0017AF51 0x00408040 0x00000000 0x00000000 + 0x1018044E 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x0003FFFF 0x0003FFFF 0x00000001 0x00000001 0x07940708 + 0x00000000 0x01400001 + + // hdr: lut inv_u + 0x29 0x01 0x00 0x09 0x00FE 0x002 0x0001000C 0xF1311148 + + + // hdr: lut inv_v + 0x29 0x01 0x00 0x09 0x00FD 0x002 0x0001000C 0xF1311348 + + + // hdr: gc + 0x29 0x01 0x00 0x09 0x00A0 0x003 0x0001000C 0xF1311548 + 0x00000800 + + // hdr: update + 0x29 0x01 0x00 0x09 0x0080 0x003 0x0001000C 0xF1311574 + 0x00000002 + + // hdr: Y5P ctrl + 0x29 0x01 0x00 0x09 0x0090 0x03 0x0001000C 0xF1311144 + 0x01400001 + + // hdr: lut2 ctrl + 0x29 0x01 0x00 0x09 0x0091 0x03 0x0001000C 0xF131111C + 0x00140000 + + // hdr: luty ctrl + 0x29 0x01 0x00 0x09 0x0092 0x03 0x0001000C 0xF131102C + 0x00000020 + + // hdr: resolution + 0x29 0x01 0x00 0x09 0x0093 0x04 0x0001000C 0xF1311020 + 0x05A00C60 0x0000003A + + // hdr: ext 0 + 0x29 0x00 0x00 0x09 0x0070 0x003 0x00000000 0xF12D0028 + 0x10000000 + + // hdr: ext 1 + 0x29 0x01 0x00 0x09 0x0070 0x00B 0x00000000 0xF12D0004 + 0x1F7115F4 0x0AAA27E8 0x00000000 0x061E0294 0x0FFE0F80 0x061E0294 + 0x0FFE0F80 0x061E0294 0x0FFE0F80 + + // hdr: ext - dma + 0x29 0x01 0x00 0x09 0x0070 0x00C 0x0001000C 0xF131154C + 0x1F7115F4 0x0AAA27E8 0x00000000 0x061E0294 0x0FFE0F80 0x061E0294 + 0x0FFE0F80 0x061E0294 0x0FFE0F80 0x10000000 + + // pwil: ctrl 0 + 0x29 0x01 0x00 0x03 0x00F0 0x00B 0x0001000C 0xF1310608 + 0xA0E82014 0x00C8B794 0x39020160 0x50000016 0x0C6005A0 0x00000000 + 0x038402D0 0x038402D0 0x00000080 + + // pwil: ctrl 1 + 0x29 0x01 0x00 0x03 0x00F1 0x006 0x0001000C 0xF1310608 + 0xA0E82014 0x00C8B794 0x39020160 0x50000016 + + // pwil: csc-0 (hdr) + 0x29 0x01 0x00 0x03 0x0090 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x09510951 0x00000951 0x11227E80 0x7ACC0D6E 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-1 (hdr) + 0x29 0x01 0x00 0x03 0x0091 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x095A095A 0x0014095A 0x051F7FEC 0x7EFC0104 0x00007D12 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-2 (hdr) + 0x29 0x01 0x00 0x03 0x0092 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x095A0000 0x00000000 0x09250000 0x00000925 0x00000000 + 0x00002000 0x00000000 0x00002000 + + // pwil: csc-3 (hdr) + 0x29 0x01 0x00 0x03 0x0093 0x0B 0x0001000C 0xF1310630 + 0x0000000F 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-4 (hdr) + 0x29 0x01 0x00 0x03 0x0094 0x0B 0x0001000C 0xF1310630 + 0x00000011 0x09DC773A 0x090B04A8 0x13777E3B 0x013A090B 0x00007132 + 0x000FFB58 0x000FFB58 0x000FFB58 + + // pwil: csc-5 (frc) + 0x29 0x01 0x00 0x03 0x0095 0x0B 0x0001000C 0xF1310630 + 0x00000011 0x04B27CA7 0x7F597D5A 0x040000E9 0x02640400 0x00007EA6 + 0x00002000 0x00000000 0x00002000 + + // pwil: dpcd + 0x29 0x01 0x00 0x03 0x00F4 0x00C 0x0001000C 0xF1310654 + 0x00000000 0x00010000 0x00000200 0x00010001 0x00010001 0x000002D0 + 0x00000200 0x000004FC 0x00000000 0x05000000 + + // pwil: piad_info + 0x29 0x01 0x00 0x03 0x0020 0x004 0x0001000C 0xF131067C + 0x05000008 0x00000063 + + // pwil: ctrl graphic + 0x29 0x01 0x00 0x03 0x00A0 0x00C 0x0001000C 0xF1310684 + 0xE4100010 0x00030AAA 0x00000000 0x0C6005A0 0x0C6005A0 0x00000093 + 0x00040000 0x00000000 0x0C6005A0 0x0C6005A0 + + // pwil: ctrl graphic dual + 0x29 0x01 0x00 0x03 0x00A1 0x00C 0x0001000C 0xF1310684 + 0xE4100010 0x00030AAA 0x00000000 0x0C6005A0 0x0C6005A0 0x00000093 + 0x000B0000 0x00000000 0x0C6005A0 0x0C6005A0 + + // pwil: channel-order-0 + 0x29 0x01 0x00 0x03 0x0060 0x03 0x0001000C 0xF1310684 + 0xC9110010 + + // pwil: channel-order-1 + 0x29 0x01 0x00 0x03 0x0061 0x03 0x0001000C 0xF1310684 + 0xE4100010 + + // pwil: channel-order-2 + 0x29 0x01 0x00 0x03 0x0062 0x03 0x0001000C 0xF1310684 + 0xE4100010 + + // pwil: video + 0x29 0x01 0x00 0x03 0x00B0 0x00D 0x0001000C 0xF13106AC + 0xE4100030 0x00030AAA 0x92071B09 0x00000000 0x0C6005A0 0x0C6005A0 + 0x0000003B 0x00040000 0x00000000 0x0C6005A0 0x07080240 + + // pwil: video dual + 0x29 0x01 0x00 0x03 0x00B1 0x00D 0x0001000C 0xF13106AC + 0xE4100030 0x00030AAA 0x92071B09 0x00000000 0x0C6005A0 0x0C6005A0 + 0x00000034 0x000B0000 0x00000000 0x0C6005A0 0x07080200 + + // pwil: cursor + 0x29 0x01 0x00 0x03 0x00C0 0x00D 0x0001000C 0xF13106D8 + 0xE4D00010 0x00000AAA 0x00000000 0x0C6005A0 0x0C6005A0 0x00000010 + 0x00020000 0x00000000 0x00000000 0x00000000 0x0C6005A0 + + // pwil: disp + 0x29 0x01 0x00 0x03 0x00D0 0x009 0x0001000C 0xF1310704 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00008200 + 0x00000000 + + // pwil: disp ctrl0 hw bitmask + 0x29 0x00 0x00 0x03 0x00D1 0x02 0x00000008 0xF12410B0 + 0x29 0x01 0x00 0x03 0x00D1 0x04 0x00000005 0xF12410B0 0x00000040 0x00000000 + + // pwil: frc + 0x29 0x01 0x00 0x03 0x00F2 0x009 0x0001000C 0xF1310720 + 0x0C5F0000 0x059F0000 0x00000003 0x00040000 0x00040000 0x00300000 + 0x00000000 + + // pwil: ad_blend + 0x29 0x01 0x00 0x03 0x00F3 0x03 0x0001000C 0xF1311E30 + 0x00000063 + + // pwil: pps sel + 0x29 0x01 0x00 0x03 0x0040 0x003 0x0001000C 0xF131062C + 0x00000004 + + // pwil: update + 0x29 0x01 0x00 0x03 0x0080 0x003 0x0001000C 0xF131073C + 0x00000100 + + // pwil: force update + 0x29 0x01 0x00 0x03 0x0030 0x03 0xFFFFFFF4 + 0xF1250000 0x00000200 + + // dpp: csc-0 + 0x29 0x01 0x00 0x0E 0x0040 0x0B 0x0001000C 0xF1310850 + 0x00000011 0x08000000 0x00000000 0x08000000 0x00000800 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: csc-1 + 0x29 0x01 0x00 0x0E 0x0041 0x0B 0x0001000C 0xF1310850 + 0x00000011 0x06A00000 0x00000000 0x06A00000 0x000006A0 0x00000000 + 0x0B000B00 0x00000B00 0x00000B00 + + // dpp: cm_csc-0 + 0x29 0x01 0x00 0x0E 0x0060 0x0B 0x0001000C 0xF1310A08 + 0x00000018 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: cm_csc-0 + 0x29 0x01 0x00 0x0E 0x0061 0x0B 0x0001000C 0xF1310A08 + 0x00000011 0x08880000 0x00000000 0x08880000 0x00000888 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: init + 0x29 0x01 0x00 0x0E 0x00F0 0x00C 0x0001000C 0xF131084C + 0x00014000 0x00000010 0x09510000 0x7FFE094E 0x10E47E4C 0x7BBD0E56 + 0x00000000 0x00000000 0x00000000 0x00000000 + + // dpp: init s curve + 0x29 0x01 0x00 0x0E 0x00F1 0x28 0x0001000C 0xF1310A2C + 0xB29500A4 0x80808080 0x00000002 0x00FFFFFF 0x00580800 0x006155E0 + 0x0066D648 0x006A568B 0x006CE6BC 0x006F46E3 0x00711703 0x0072B71E + 0x00742738 0x0075874C 0x0076B762 0x0077C773 0x0078C784 0x0079A792 + 0x007A97A1 0x007B67AF 0x000007BC 0x007C87C2 0x007D47CE 0x007DE7D9 + 0x007E97E3 0x007F27ED 0x007FC7F7 0x0080A801 0x00818811 0x0082381D + 0x0082A827 0x0082E82C 0x0082E82F 0x0082C82D 0x00824829 0x0081881F + 0x0080080E 0x00000800 + + // dpp: s curve level 0 + 0x29 0x01 0x00 0x0E 0x0070 0x24 0x0001000C 0xF1310A3C + 0x00713800 0x00727721 0x0072C72A 0x0073072F 0x00734732 0x00737735 + 0x0073C739 0x0074173F 0x00748744 0x0075074C 0x00758754 0x0076275D + 0x0076B767 0x00777771 0x0078477E 0x0079178A 0x00000797 0x007A679E + 0x007B57AD 0x007C47BD 0x007D57CC 0x007E67DD 0x007F87EF 0x0080A801 + 0x00818811 0x0082381D 0x0082A827 0x0082E82C 0x0082E82F 0x0082C82D + 0x00824829 0x0081881F 0x0080080E 0x00000800 + + // dpp: s curve level 1 + 0x29 0x01 0x00 0x0E 0x0071 0x24 0x0001000C 0xF1310A3C + 0x003E0800 0x0050B490 0x005BA568 0x006375FB 0x0069C66C 0x006F46CD + 0x0074271D 0x00784765 0x007C27A4 0x007FB7DE 0x00822810 0x00840831 + 0x0085784C 0x00868860 0x00876870 0x0088187C 0x00000885 0x0088A888 + 0x0088E88D 0x00890890 0x00890890 0x0088E88F 0x0088A88C 0x00885888 + 0x0087F882 0x0087687B 0x0086D872 0x0085285F 0x0083C846 0x0082B833 + 0x0081E824 0x00812818 0x0080080B 0x00000800 + + // dpp: s curve disable + 0x29 0x01 0x00 0x0E 0x0050 0x03 0x0001000C 0xF1310A2C + 0xB29500A4 + + // dpp: s curve enable + 0x29 0x01 0x00 0x0E 0x0051 0x03 0x0001000C 0xF1310A2C + 0xB29500A5 + + // dpp: gamma disable + 0x29 0x01 0x00 0x0E 0x0000 0x03 0x0001000C 0xF131084C + 0x00014000 + + // dpp: gamma enable + 0x29 0x01 0x00 0x0E 0x0001 0x03 0x0001000C 0xF131084C + 0x00014040 + + // dpp: gamma + 0x29 0x01 0x00 0x0E 0x00FE 0x002 0x0001000C 0xF1310874 + + + // dpp: dither + 0x29 0x01 0x00 0x0E 0x00F8 0x002 0x0001000C 0xF1310AC4 + + + // dpp: dpp_2 + 0x29 0x01 0x00 0x0E 0x00A0 0x003 0x0001000C 0xF1310BC4 + 0x00002100 + + // dpp: update + 0x29 0x01 0x00 0x0E 0x0080 0x003 0x0001000C 0xF1310BC8 + 0x00000001 + + // peaking2d: level0 + 0x29 0x01 0x00 0x0C 0x0000 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00200040 + 0x00000000 0x00000000 0x00FF00FF 0x00000000 0x00000000 0x000000E0 + + // peaking2d: level1 + 0x29 0x01 0x00 0x0C 0x0001 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00020002 0x00000000 + 0x03F40008 0x00200012 0x00020002 0x00000000 0x03F40008 0x00200012 + 0x00080008 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000000 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level2 + 0x29 0x01 0x00 0x0C 0x0002 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00040004 0x00000000 + 0x03F80010 0x00200012 0x00040004 0x00000000 0x03F80010 0x00200012 + 0x00100010 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level3 + 0x29 0x01 0x00 0x0C 0x0003 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00070007 0x00000000 + 0x03F70010 0x00200012 0x00070007 0x00000000 0x03F70010 0x00200012 + 0x00120012 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level4 + 0x29 0x01 0x00 0x0C 0x0004 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00090009 0x00000000 + 0x03F70010 0x00200012 0x00090009 0x00000000 0x03F70010 0x00200012 + 0x00140014 0x00000000 0x03F40000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: csc 0 + 0x29 0x01 0x00 0x0C 0x0010 0x04 0x0001000C 0xF13107A0 + 0x00000009 0x00000009 + + // peaking2d: csc 1 + 0x29 0x01 0x00 0x0C 0x0011 0x04 0x0001000C 0xF13107A0 + 0x00000009 0x00000008 + + // peaking2d: init + 0x29 0x01 0x00 0x0C 0x00F0 0x01C 0x0001000C 0xF1310740 + 0x001E000A 0x0000000A 0x00E00020 0x025800A0 0x00780028 0x00000028 + 0x00E00020 0x032000A0 0x003C003C 0x00000014 0x00800000 0x03200078 + 0x003C003C 0x0000003C 0x00000000 0x03FC0000 0x00200040 0x00200040 + 0x00030000 0x00000000 0x00FF00FF 0x00FF0004 0x003F03FF 0x000000F0 + 0x00000000 0x00000000 + + // peaking2d: gc idle clk off + 0x29 0x01 0x00 0x0C 0x00A0 0x003 0x0001000C 0xF13107A8 + 0x00010800 + + // peaking2d: gc idle clk on + 0x29 0x01 0x00 0x0C 0x00A1 0x03 0x0001000C 0xF13107A8 + 0x00010803 + + // peaking2d: update + 0x29 0x01 0x00 0x0C 0x0080 0x003 0x0001000C 0xF13107AC + 0x00000001 + + // lce: level 0 + 0x29 0x01 0x00 0x0D 0x0000 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A5 0x00003C64 0x00201002 + + // lce: level 1 + 0x29 0x01 0x00 0x0D 0x0001 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 2 + 0x29 0x01 0x00 0x0D 0x0002 0x12 0x0001000C 0xF1310C3C + 0x028E1096 0x0A140000 0x002FFFFF 0x0E100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x00006446 0x0000280A 0x000FFC14 0x03FC0020 + 0x0080100A 0x000040A6 0x00003C64 0x000A0602 + + // lce: level 3 + 0x29 0x01 0x00 0x0D 0x0003 0x12 0x0001000C 0xF1310C3C + 0x010E1096 0x0A140000 0x002FFFFF 0x06100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x0000B464 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 4 + 0x29 0x01 0x00 0x0D 0x0004 0x12 0x0001000C 0xF1310C3C + 0x018E1096 0x0A140000 0x002FFFFF 0x10100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x0000B464 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00100802 + + // lce: level 5 + 0x29 0x01 0x00 0x0D 0x0005 0x12 0x0001000C 0xF1310C3C + 0x064E1096 0x0A140000 0x002FFFFF 0x191005DC 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C800C8 0x000168A5 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 6 + 0x29 0x01 0x00 0x0D 0x0006 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A5 0x00003C64 0x00201002 + + // lce: level 7 + 0x29 0x01 0x00 0x0D 0x0007 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 8 + 0x29 0x01 0x00 0x0D 0x0008 0x12 0x0001000C 0xF1310C3C + 0x028E1096 0x0A140000 0x002FFFFF 0x0610012C 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x00006446 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 9 + 0x29 0x01 0x00 0x0D 0x0009 0x12 0x0001000C 0xF1310C3C + 0x03CE1096 0x0A140000 0x002FFFFF 0x1E100384 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x0000B46E 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 10 + 0x29 0x01 0x00 0x0D 0x000A 0x12 0x0001000C 0xF1310C3C + 0x050E1096 0x0A140000 0x002FFFFF 0x1E1004B0 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x0001186E 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 11 + 0x29 0x01 0x00 0x0D 0x000B 0x12 0x0001000C 0xF1310C3C + 0x064E1096 0x0A140000 0x002FFFFF 0x1E1005DC 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x000000C8 0x000168A5 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: gra_det 0 + 0x29 0x01 0x00 0x0D 0x0010 0x03 0x0001000C 0xF1310C7C + 0x2804003C + + // lce: gra_det 1 + 0x29 0x01 0x00 0x0D 0x0011 0x03 0x0001000C 0xF1310C7C + 0x2804083C + + // lce: reserved: TODO + 0x29 0x00 0x00 0x0D 0x00F0 0x003 0x0001000C 0xF1310C84 + 0xC77F0437 + + // lce: init + 0x29 0x01 0x00 0x0D 0x00F0 0x02F 0x0001000C 0xF1310BCC + 0x059F0000 0x0C5F0000 0x0002C940 0x0002C940 0x0002C700 0x0002C700 + 0x0002C32E 0x0002C820 0x0002C32E 0x0002C44C 0x0002C210 0x0027A120 + 0x00000100 0x00240120 0x00480360 0x004F427A 0x009E876E 0x00066667 + 0x00066667 0x00000412 0x00010453 0x00000419 0x00010625 0x00040000 + 0x00000000 0x00000B63 0x0000052D 0x000000EC 0x000E1096 0x0A140000 + 0x002FFFFF 0x0F100100 0x00001010 0x17C7D1F4 0x1F4029F4 0x00000096 + 0x00006464 0x0000280A 0x000FFC10 0x03E80010 0x0081100A 0x000040A5 + 0x00003C64 0x00201002 0x2804003C + + // lce: gc + 0x29 0x01 0x00 0x0D 0x00A0 0x003 0x0001000C 0xF1310C80 + 0x00000000 + + // lce: read + 0x29 0x01 0x00 0x0D 0x0070 0x0D4 0x0001000C 0xF1310C88 + 0x40000000 0x00000043 0x06010020 0x0C028080 0x120400E0 0x18058140 + 0x1E0701A0 0x24088200 0x2A0A0260 0x300B82C0 0x360D0320 0x3C0E8380 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x000003E0 0x01002000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + + // lce: update + 0x29 0x01 0x00 0x0D 0x0080 0x003 0x0001000C 0xF1310FD0 + 0x00000004 + + // lce: read update + 0x29 0x01 0x00 0x0D 0x0071 0x003 0x0001000C 0xF1310FD4 + 0x80000001 + + // cm: 6axis 0 + 0x29 0x01 0x00 0x0A 0x0000 0x04 0x0001000C 0xF13107B0 + 0x0820E000 0x03400010 + + // cm: 6axis 1 + 0x29 0x01 0x00 0x0A 0x0001 0x04 0x0001000C 0xF13107B0 + 0x0820E800 0x03000000 + + // cm: 6axis 2 + 0x29 0x01 0x00 0x0A 0x0002 0x04 0x0001000C 0xF13107B0 + 0x0820EC00 0x03000000 + + // cm: 6axis 3 + 0x29 0x01 0x00 0x0A 0x0003 0x04 0x0001000C 0xF13107B0 + 0x0820EFC0 0x03000000 + + // cm: color 0 + 0x29 0x01 0x00 0x0A 0x0020 0x08 0x0001000C 0xF13107F0 + 0x382A0C12 0x36280C1A 0x66510C0E 0x47390C12 0x120A0C36 0x55440C0E + + // cm: color 1 + 0x29 0x01 0x00 0x0A 0x0021 0x08 0x0001000C 0xF13107F0 + 0x382A0C12 0x500A2836 0x500A2836 0x500A2836 0x500A2836 0x55440C0E + + // cm: ftc 0 + 0x29 0x01 0x00 0x0A 0x0010 0x10 0x0001000C 0xF13107B8 + 0x7A067844 0x1C43FF10 0x15450018 0x00002215 0x3FE6B47F 0x00A05000 + 0x28ABF44B 0x7FF8103F 0x7840473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 1 + 0x29 0x01 0x00 0x0A 0x0011 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15450018 0x00282215 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80CBF 0x7840473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 2 + 0x29 0x01 0x00 0x0A 0x0012 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15280418 0x00201815 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80C3F 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 3 + 0x29 0x01 0x00 0x0A 0x0013 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15280418 0x002C1815 0x3FE6B47F 0x08C06018 + 0x2853F410 0x7FF80A3F 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 4 + 0x29 0x01 0x00 0x0A 0x0014 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15450018 0x00282215 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80CBF 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: csc 0 + 0x29 0x01 0x00 0x0A 0x0040 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0E307D40 0x7A480B38 0x00000000 + + // cm: csc 1 + 0x29 0x01 0x00 0x0A 0x0041 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x07177EA0 0x7D25059C 0x00000000 + + // cm: csc 2 + 0x29 0x01 0x00 0x0A 0x0045 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0F0D7EAF 0x7B6E0BCC 0x00000000 + + // cm: csc 3 + 0x29 0x01 0x00 0x0A 0x0046 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0F0D7EAF 0x7B6E0BCC 0x00000000 + + // cm: init + 0x29 0x00 0x00 0x0A 0x00F0 0x012 0x0001000C 0xF13107B0 + 0x0820EFC0 0x13000000 0x7A067844 0x1C43FF10 0x15450018 0x002C2215 + 0x3FE6B47F 0x00A05000 0x28ABF44B 0x7FF8103F 0x7840473A 0x005537B7 + 0x88034C40 0x708200D3 0x88034C40 0x70820384 + + // cm: init csc + 0x29 0x01 0x00 0x0A 0x00F0 0x00B 0x0001000C 0xF1310820 + 0x0000001D 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // cm: gc + 0x29 0x01 0x00 0x0A 0x00A0 0x003 0x0001000C 0xF1310844 + 0x00000800 + + // cm: update + 0x29 0x01 0x00 0x0A 0x0080 0x003 0x0001000C 0xF1310848 + 0x00000100 + + // scaler1d + 0x29 0x01 0x00 0x0B 0x00F0 0x013 0x0001000C 0xF1311598 + 0x00026620 0x00000441 0x000E147A 0x000E147A 0x00006410 0x07080708 + 0x00000003 0x00000003 0x00000000 0x0000001E 0x02400240 0x00140000 + 0x00140000 0x00000003 0x00000003 0x00006410 0x00000000 + + // scaler1d dual + 0x29 0x01 0x00 0x0B 0x00F1 0x013 0x0001000C 0xF1311598 + 0x00026620 0x00000441 0x000E147A 0x000E147A 0x00006410 0x07080708 + 0x00000003 0x00000003 0x00000000 0x0000001E 0x02000200 0x00168000 + 0x00168000 0x00000003 0x00000003 0x00006410 0x00000000 + + // scaler1d: gc + 0x29 0x01 0x00 0x0B 0x00A0 0x003 0x0001000C 0xF13115DC + 0x00000800 + + // dbc: gc + 0x29 0x01 0x00 0x0F 0x00A0 0x003 0x0001000C 0xF1311748 + 0x00000800 + + // dbc: init + 0x29 0x00 0x00 0x0F 0x00F0 0x037 0x0001000C 0xF13118D0 + 0x50850421 0x00000000 0x00000000 0x0000003F 0x00000000 0x00000080 + 0x0000012C 0x00000400 0x00000600 0x00000E00 0x000002EC 0x00000400 + 0x00000448 0x00000197 0x000002C5 0x00000300 0x000000D6 0x00000067 + 0x00000009 0x00000043 0x00000026 0x00000004 0x00000140 0x000002D8 + 0x0000014B 0x0000003F 0x00000002 0x00000FFF 0x000002D8 0x0000014B + 0x00000000 0x0000000E 0x00000800 0x00000000 0x00000B38 0x00000800 + 0x00007D3E 0x00007A4A 0x00000800 0x00000E2C 0x00007FFE 0x00000800 + 0x00000000 0x00000B38 0x00000800 0x00007D3E 0x00007A4A 0x00000800 + 0x00000E2C 0x00007FFE 0x00000000 0x000003FF 0x00000FFF + + // dbc: init plcdcompw + 0x29 0x01 0x00 0x0F 0x00F0 0x023 0x0001000C 0xF131174C + 0x000003FF 0x000003E0 0x000003C0 0x000003A0 0x00000380 0x00000360 + 0x00000340 0x00000320 0x00000300 0x000002E6 0x000002CD 0x000002B3 + 0x0000029A 0x00000280 0x00000266 0x0000024D 0x00000233 0x0000021A + 0x00000200 0x000001E6 0x000001CD 0x000001B3 0x0000019A 0x00000180 + 0x00000166 0x0000013A 0x0000010D 0x000000E0 0x000000B3 0x00000087 + 0x0000005A 0x0000002D 0x00000000 + + // dbc: COREX0K0 + 0x29 0x01 0x00 0x0F 0x00FE 0x002 0x0001000C 0xF13117D0 + + + // dbc: read + 0x29 0x01 0x00 0x0F 0x0070 0x01A 0x0001000C 0xF13119A4 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000FFF 0x00000FFF + 0x00001000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x000003FF 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000063 0x00000000 0x00000FFF + + // dbc: off + 0x29 0x01 0x00 0x0F 0x0000 0x03 0x0001000C 0xF13118D0 + 0x40850423 + + // dbc: on + 0x29 0x01 0x00 0x0F 0x0001 0x03 0x0001000C 0xF13118D0 + 0x40840423 + + // dbc: level 0 + 0x29 0x01 0x00 0x0F 0x0010 0x04 0x0001000C 0xF1311934 + 0x00000000 0x00000000 + + // dbc: level 1 + 0x29 0x01 0x00 0x0F 0x0011 0x04 0x0001000C 0xF1311934 + 0x00000027 0x00000002 + + // dbc: level 2 + 0x29 0x01 0x00 0x0F 0x0012 0x04 0x0001000C 0xF1311934 + 0x00000022 0x00000002 + + // dbc: level 3 + 0x29 0x01 0x00 0x0F 0x0013 0x04 0x0001000C 0xF1311934 + 0x0000001B 0x00000002 + + // dbc: compenk table 0 + 0x29 0x01 0x00 0x0F 0x0020 0x03 0x0001000C 0xF13118D4 + 0x00000000 + + // dbc: compenk table 1 + 0x29 0x01 0x00 0x0F 0x0021 0x03 0x0001000C 0xF13118D4 + 0x00000001 + + // dbc: income table 0 + 0x29 0x01 0x00 0x0F 0x0030 0x03 0x0001000C 0xF13118D8 + 0x00000000 + + // dbc: income table 1 + 0x29 0x01 0x00 0x0F 0x0031 0x03 0x0001000C 0xF13118D8 + 0x00000001 + + // dbc: RGB in + 0x29 0x01 0x00 0x0F 0x0040 0x03 0x0001000C 0xF131194C + 0x00000006 + + // dbc: YUV in + 0x29 0x01 0x00 0x0F 0x0041 0x03 0x0001000C 0xF131194C + 0x00000007 + + // dsc_dec: init + 0x29 0x01 0x00 0x07 0x00F0 0x01A 0x0001000C 0xF13115E0 + 0x00480150 0x01E001E0 0xAB000011 0x600CA030 0x1000A005 0x8403D002 + 0xFF1B9A01 0xD1011900 0x09000E00 0xD605CD04 0xEC100016 0x00201007 + 0x330F0F06 0x382A1C0E 0x69625446 0x7B797770 0x02027E7D 0x402A0022 + 0xFC3ABE32 0xF83AFA3A 0x783B383B 0xB64B763B 0xF44BB44B 0x347CF45B + + // dsc_dec: gc + 0x29 0x01 0x00 0x07 0x00A0 0x003 0x0001000C 0xF1311640 + 0x00000800 + + // dsc_dec: update + 0x29 0x01 0x00 0x07 0x0080 0x003 0x0001000C 0xF1311644 + 0x00000001 + + // dsc_enc: init + 0x29 0x01 0x00 0x08 0x00F0 0x042 0x0001000C 0xF1311648 + 0x00000003 0x00000002 0x00F001E0 0x000202D0 0x00F001C2 0x00003840 + 0x00003880 0x00001C20 0xC0002000 0x00F002D0 0x00F001E0 0x000202D0 + 0x00F001C2 0x00003840 0x00003880 0x00001C20 0x00002000 0x00F002D0 + 0x00000000 0xAB000011 0x600CA030 0x1000A005 0x8403D002 0xD8019A01 + 0xD1011900 0x09000E00 0xD605CD04 0xEC100016 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x02027E7D 0x402A0022 0xFC3ABE32 + 0xF83AFA3A 0x783B383B 0xB64B763B 0xF44BB44B 0x347CF45B 0xAB000011 + 0x600CA030 0x1000A005 0x8403D002 0xD8019A01 0xD1011900 0x09000E00 + 0xD605CD04 0xEC100016 0x00201007 0x330F0F06 0x382A1C0E 0x69625446 + 0x7B797770 0x02027E7D 0x402A0022 0xFC3ABE32 0xF83AFA3A 0x783B383B + 0xB64B763B 0xF44BB44B 0x347CF45B 0x00000004 + + // dma: init + 0x29 0x01 0x00 0x11 0x00F0 0x15C 0x0001000C 0xF1310000 + 0x80080608 0xF1240000 0x80010628 0xF1240038 0x8001062C 0xF1240054 + 0x80090630 0xF1240078 0x800A0654 0xF12400A0 0x8001067C 0xF1240108 + 0x80010680 0xF1240120 0x800A0684 0xF1241000 0x800B06AC 0xF1241028 + 0x800B06D8 0xF1241084 0x80070704 0xF12410B4 0x80070720 0xF12410F0 + 0x8001073C 0xF1250000 0x80180740 0xF1A00000 0x800207A0 0xF1A0006C + 0x800107A8 0xF1A00060 0x800107AC 0xF1A00090 0x801007B0 0xF1560000 + 0x800107F0 0xF1560050 0x800107F4 0xF156006C 0x800107F8 0xF1560088 + 0x800107FC 0xF15600A4 0x80010800 0xF15600C0 0x80010804 0xF15600DC + 0x80010808 0xF1560058 0x8001080C 0xF1560074 0x80010810 0xF1560090 + 0x80010814 0xF15600AC 0x80010818 0xF15600C8 0x8001081C 0xF15600E4 + 0x80090820 0xF1560130 0x80010844 0xF1560118 0x80010848 0xF1560160 + 0x8001084C 0xF1580000 0x80090850 0xF1580014 0x80630874 0xF1580100 + 0x80020A00 0xF158003C 0x80090A08 0xF1580048 0x80030A2C 0xF158006C + 0x80010A38 0xF1580394 0x80220A3C 0xF1580078 0x80400AC4 0xF1580294 + 0x80010BC4 0xF1580008 0x80010BC8 0xF1580290 0x84020BCC 0xF1520064 + 0x840F0BD4 0xF1520094 0x840B0C10 0xF15200F8 0x84100C3C 0xF1520000 + 0x84010C7C 0xF1520054 0x84010C80 0xF1520058 0x84010C84 0xF1520070 + 0xC4D20C88 0xF1531008 0x84010FD0 0xF1531000 0xC4010FD4 0xF1531004 + 0x805C0FD8 0xF12C0000 0x81001148 0xF12C1400 0x80011548 0xF12CFF08 + 0xC00A154C 0xF12D0004 0x80011574 0xF12D0000 0x80061578 0xF1220000 + 0x80011590 0xF1220028 0x80011594 0xF1220064 0x80111598 0xF1A20000 + 0x800115DC 0xF1A20044 0x800215E0 0xF1680000 0x801615E8 0xF168000C + 0x80011640 0xF1680008 0x80011644 0xF169FF00 0x880A1648 0xF1640000 + 0x88081670 0xF1640030 0x88011690 0xF1640054 0x882D1694 0xF1640064 + 0x84011748 0xF1500404 0x8421174C 0xF1500178 0x844017D0 0xF1500304 + 0x840518D0 0xF1500000 0x841218E4 0xF1500014 0x8402192C 0xF1500080 + 0x84021934 0xF15000C8 0x8401193C 0xF15000DC 0x84021940 0xF1500100 + 0x84011948 0xF150015C 0x8413194C 0xF150040C 0x84031998 0xF1500458 + 0xC41819A4 0xF1518000 0x80031A04 0xF1400000 0x80011A10 0xF1400010 + 0xC0011A14 0xF1400010 0x80011A18 0xF140001C 0x80031A1C 0xF1400024 + 0x80011A28 0xF14000A8 0x80011A2C 0xF14000C8 0x80041A30 0xF1400104 + 0x80021A40 0xF140011C 0x80011A48 0xF141FF00 0x80011A4C 0xF17A0000 + 0x80011A50 0xF17BE000 0x0C191A54 0xF1720000 0x0C011AB8 0xF173FF00 + 0x0C0A1ABC 0xF1700000 0x0C011AE4 0xF1700054 0x0C161AE8 0xF1700064 + 0x0C011B40 0xF1700114 0x80121B44 0xF1A40000 0x8C2F1B8C 0xF16A0000 + 0x8C011C48 0xF16BFF00 0x8C2F1C4C 0xF16C0000 0x8C011D08 0xF16DFF00 + 0x8C0A1D0C 0xF1620000 0x8C081D34 0xF1620030 0x8C011D54 0xF1620054 + 0x8C2D1D58 0xF1620064 0x80071E0C 0xF1540000 0x80011E28 0xF1540060 + 0x80011E2C 0xF1550030 0x80011E30 0xF1240120 0x80011E34 0xF1240014 + 0x9C011E38 0xF1800808 0x9C011E3C 0xF1800818 0x9C011E40 0xF1800A00 + 0x9C011E44 0xF1800A08 0x9C011E48 0xF1800238 0x9C021E4C 0xF1800300 + 0x9C011E54 0xF1801804 0x9C011E58 0xF1800104 0x9C021E5C 0xF1800144 + 0x9C011E64 0xF1800080 0x9C011E68 0xF18C0200 0x9C011E6C 0xF18C0004 + 0x9C011E70 0xF18C0210 0x9C031E74 0xF1880050 0x9C011E80 0xF1880004 + 0x9C011E84 0xF1880020 0x9C041E88 0xF188002C 0x9C011E98 0xF1880044 + 0x9C041E9C 0xF1880010 0x9C021EAC 0xF1880008 0x9C011EB4 0xF1880000 + 0x9C011EB8 0xF1800010 0xB0011EBC 0xF1840808 0xB0011EC0 0xF1840818 + 0xB0011EC4 0xF1840A00 0xB0011EC8 0xF1840A08 0xB0011ECC 0xF1840238 + 0xB0011ED0 0xF1840300 0xB0011ED4 0xF1840304 0xB0011ED8 0xF1841804 + 0xB0011EDC 0xF1840104 0xB0021EE0 0xF1840144 0xB0011EE8 0xF1840080 + 0xB0021EEC 0xF16E0000 0xB0161EF4 0xF16E000C 0xB0011F4C 0xF16E0008 + 0xB0011F50 0xF16FFF00 0xB0031F54 0xF17C0000 0xB0011F60 0xF17D1000 + 0xB0061F64 0xF1280004 0xB0011F7C 0xF1280030 0xB0021F80 0xF1280038 + 0xB00D1F88 0xF1281000 0xB0011FBC 0xF1280000 0xB0011FC0 0xF1290000 + 0x9C011FC4 0xF1800A14 0x9C011FC8 0xF1800A1C 0x9C011FCC 0xF1800A24 + 0x9C011FD0 0xF1800A2C 0x9C011FD4 0xF180001C 0xB0011FD8 0xF1840A14 + 0xB0011FDC 0xF1840A1C 0xB0011FE0 0xF1840A24 0xB0011FE4 0xF1840A2C + 0x80011FE8 0xF1540030 0x80011FEC 0xF1540040 + + // dma: init no read + 0x29 0x01 0x00 0x11 0x00F1 0x15C 0x0001000C 0xF1310000 + 0x80080608 0xF1240000 0x80010628 0xF1240038 0x8001062C 0xF1240054 + 0x80090630 0xF1240078 0x800A0654 0xF12400A0 0x8001067C 0xF1240108 + 0x80010680 0xF1240120 0x800A0684 0xF1241000 0x800B06AC 0xF1241028 + 0x800B06D8 0xF1241084 0x80070704 0xF12410B4 0x80070720 0xF12410F0 + 0x8001073C 0xF1250000 0x80180740 0xF1A00000 0x800207A0 0xF1A0006C + 0x800107A8 0xF1A00060 0x800107AC 0xF1A00090 0x801007B0 0xF1560000 + 0x800107F0 0xF1560050 0x800107F4 0xF156006C 0x800107F8 0xF1560088 + 0x800107FC 0xF15600A4 0x80010800 0xF15600C0 0x80010804 0xF15600DC + 0x80010808 0xF1560058 0x8001080C 0xF1560074 0x80010810 0xF1560090 + 0x80010814 0xF15600AC 0x80010818 0xF15600C8 0x8001081C 0xF15600E4 + 0x80090820 0xF1560130 0x80010844 0xF1560118 0x80010848 0xF1560160 + 0x8001084C 0xF1580000 0x80090850 0xF1580014 0x80630874 0xF1580100 + 0x80020A00 0xF158003C 0x80090A08 0xF1580048 0x80030A2C 0xF158006C + 0x80010A38 0xF1580394 0x80220A3C 0xF1580078 0x80400AC4 0xF1580294 + 0x80010BC4 0xF1580008 0x80010BC8 0xF1580290 0x84020BCC 0xF1520064 + 0x840F0BD4 0xF1520094 0x840B0C10 0xF15200F8 0x84100C3C 0xF1520000 + 0x84010C7C 0xF1520054 0x84010C80 0xF1520058 0x84010C84 0xF1520070 + 0x44D20C88 0xF1531008 0x84010FD0 0xF1531000 0x44010FD4 0xF1531004 + 0x805C0FD8 0xF12C0000 0x81001148 0xF12C1400 0x80011548 0xF12CFF08 + 0x400A154C 0xF12D0004 0x80011574 0xF12D0000 0x80061578 0xF1220000 + 0x80011590 0xF1220028 0x80011594 0xF1220064 0x80111598 0xF1A20000 + 0x800115DC 0xF1A20044 0x800215E0 0xF1680000 0x801615E8 0xF168000C + 0x80011640 0xF1680008 0x80011644 0xF169FF00 0x880A1648 0xF1640000 + 0x88081670 0xF1640030 0x88011690 0xF1640054 0x882D1694 0xF1640064 + 0x84011748 0xF1500404 0x8421174C 0xF1500178 0x844017D0 0xF1500304 + 0x840518D0 0xF1500000 0x841218E4 0xF1500014 0x8402192C 0xF1500080 + 0x84021934 0xF15000C8 0x8401193C 0xF15000DC 0x84021940 0xF1500100 + 0x84011948 0xF150015C 0x8413194C 0xF150040C 0x84031998 0xF1500458 + 0x441819A4 0xF1518000 0x80031A04 0xF1400000 0x80011A10 0xF1400010 + 0x40011A14 0xF1400010 0x80011A18 0xF140001C 0x80031A1C 0xF1400024 + 0x80011A28 0xF14000A8 0x80011A2C 0xF14000C8 0x80041A30 0xF1400104 + 0x80021A40 0xF140011C 0x80011A48 0xF141FF00 0x80011A4C 0xF17A0000 + 0x80011A50 0xF17BE000 0x0C191A54 0xF1720000 0x0C011AB8 0xF173FF00 + 0x0C0A1ABC 0xF1700000 0x0C011AE4 0xF1700054 0x0C161AE8 0xF1700064 + 0x0C011B40 0xF1700114 0x80121B44 0xF1A40000 0x8C2F1B8C 0xF16A0000 + 0x8C011C48 0xF16BFF00 0x8C2F1C4C 0xF16C0000 0x8C011D08 0xF16DFF00 + 0x8C0A1D0C 0xF1620000 0x8C081D34 0xF1620030 0x8C011D54 0xF1620054 + 0x8C2D1D58 0xF1620064 0x80071E0C 0xF1540000 0x80011E28 0xF1540060 + 0x80011E2C 0xF1550030 0x80011E30 0xF1240120 0x80011E34 0xF1240014 + 0x9C011E38 0xF1800808 0x9C011E3C 0xF1800818 0x9C011E40 0xF1800A00 + 0x9C011E44 0xF1800A08 0x9C011E48 0xF1800238 0x9C021E4C 0xF1800300 + 0x9C011E54 0xF1801804 0x9C011E58 0xF1800104 0x9C021E5C 0xF1800144 + 0x9C011E64 0xF1800080 0x9C011E68 0xF18C0200 0x9C011E6C 0xF18C0004 + 0x9C011E70 0xF18C0210 0x9C031E74 0xF1880050 0x9C011E80 0xF1880004 + 0x9C011E84 0xF1880020 0x9C041E88 0xF188002C 0x9C011E98 0xF1880044 + 0x9C041E9C 0xF1880010 0x9C021EAC 0xF1880008 0x9C011EB4 0xF1880000 + 0x9C011EB8 0xF1800010 0xB0011EBC 0xF1840808 0xB0011EC0 0xF1840818 + 0xB0011EC4 0xF1840A00 0xB0011EC8 0xF1840A08 0xB0011ECC 0xF1840238 + 0xB0011ED0 0xF1840300 0xB0011ED4 0xF1840304 0xB0011ED8 0xF1841804 + 0xB0011EDC 0xF1840104 0xB0021EE0 0xF1840144 0xB0011EE8 0xF1840080 + 0xB0021EEC 0xF16E0000 0xB0161EF4 0xF16E000C 0xB0011F4C 0xF16E0008 + 0xB0011F50 0xF16FFF00 0xB0031F54 0xF17C0000 0xB0011F60 0xF17D1000 + 0xB0061F64 0xF1280004 0xB0011F7C 0xF1280030 0xB0021F80 0xF1280038 + 0xB00D1F88 0xF1281000 0xB0011FBC 0xF1280000 0xB0011FC0 0xF1290000 + 0x9C011FC4 0xF1800A14 0x9C011FC8 0xF1800A1C 0x9C011FCC 0xF1800A24 + 0x9C011FD0 0xF1800A2C 0x9C011FD4 0xF180001C 0xB0011FD8 0xF1840A14 + 0xB0011FDC 0xF1840A1C 0xB0011FE0 0xF1840A24 0xB0011FE4 0xF1840A2C + 0x80011FE8 0xF1540030 0x80011FEC 0xF1540040 + + // dma: init ctrl + 0x29 0x01 0x00 0x11 0x00E1 0x09 0xFFFFFFF4 + 0xF1300000 0x00000001 0xF1300004 0x00000000 0xF1300008 0x00AD0000 + 0xF1300004 0x0000000F + + // dma: write core + 0x29 0x01 0x00 0x11 0x00E2 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000001 + + // dma: write lce + 0x29 0x01 0x00 0x11 0x00E3 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000002 + + // dma: read core lce + 0x29 0x01 0x00 0x11 0x00E4 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00030000 + + // dma: write all + 0x29 0x01 0x00 0x11 0x00E5 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x0000000F + + // dma: write sw channel 8 + 0x29 0x01 0x00 0x11 0x00E6 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000100 + + // dma: write sw pq + 0x29 0x01 0x00 0x11 0x00E7 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00001000 + + // dma: write dsc + 0x29 0x01 0x00 0x11 0x00E8 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000008 + + // dma: abyp write + 0x29 0x01 0x00 0x11 0x01E9 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x0000008F + + // blc_pwm: init + 0x29 0x01 0x00 0x06 0x00F0 0x03 0xFFFFFFF4 + 0xF10C0014 0x0001100A + + // blc_pwm: disable + 0x29 0x01 0x00 0x06 0x0000 0x03 0xFFFFFFF4 + 0xF10C0000 0x00001481 + + // blc_pwm: enable + 0x29 0x01 0x00 0x06 0x0001 0x03 0xFFFFFFF4 + 0xF10C0000 0x00001484 + + // psr_mif: init + 0x29 0x01 0x00 0x2D 0x00F0 0x014 0x0001000C 0xF1311A04 + 0x0BFCCE14 0x14031085 0x48004C02 0x00004082 0x00004082 0x00100E20 + 0x00091000 0x000A1000 0x002002A4 0x00004040 0x10410400 0x05A005A0 + 0x02400240 0x04980008 0x04980008 0x00020000 0x00000408 0x00000001 + + // psr_mif: init dual + 0x29 0x01 0x00 0x2D 0x00F1 0x014 0x0001000C 0xF1311A04 + 0x0BFCCE14 0x1405D085 0x48004C02 0x00004082 0x00004082 0x00100E20 + 0x00091000 0x000B0000 0x002002A4 0x00004040 0x10410400 0x05A005A0 + 0x02400240 0x04980008 0x04980008 0x00020000 0x00000408 0x00000001 + + // psr_mif: efifo_ctrl + 0x29 0x01 0x00 0x2D 0x00FD 0x03 0x0001000C 0xF1311A08 + 0x14031085 + + // psr_mif: efifo_ctrl dual + 0x29 0x01 0x00 0x2D 0x00FE 0x03 0x0001000C 0xF1311A08 + 0x1405D085 + + // osd_decomp: init + 0x29 0x01 0x00 0x2B 0x00F0 0x004 0x0001000C 0xF1311A4C + 0x00000473 0x00000100 + + // dsc_decoder_psr: init + 0x29 0x01 0x00 0x25 0x00F0 0x01C 0x0001000C 0xF1311A54 + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x600C6830 0x600CA005 + 0x9204A005 0xB2047602 0x6A692000 0x0C001400 0x04000800 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0x00000001 + + // dsc_encoder_psr: init + 0x29 0x01 0x00 0x24 0x00F0 0x024 0x0001000C 0xF1311ABC + 0x00000003 0x00000002 0x01E001E0 0x000105A0 0x01E00125 0x00388EC0 + 0x0038D900 0x000E29E0 0xC0003000 0x01E005A0 0x00000000 0x89000011 + 0x600C6830 0x600CA005 0x9204A005 0xB2047602 0x6A692000 0x0C001400 + 0x04000800 0xF1100018 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 + 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A + 0xF62AB61A 0x742B342B 0xF46B743B 0x00000004 + + // scaler_pp: init + 0x29 0x01 0x00 0x2F 0x00F0 0x014 0x0001000C 0xF1311B44 + 0x00026620 0x00000441 0x00048BA2 0x00048BA2 0x00006410 0x0C600C60 + 0x00040003 0x00040003 0x00000000 0x0000001E 0x05A005A0 0x00033333 + 0x00033333 0x00070003 0x00070003 0x00006410 0x00000000 0x00000800 + + // scaler_pp: init dual + 0x29 0x01 0x00 0x2F 0x00F1 0x014 0x0001000C 0xF1311B44 + 0x00026620 0x00000441 0x00048BA2 0x00048BA2 0x00006410 0x0C600C60 + 0x00040003 0x00040003 0x00000000 0x0000001E 0x05A005A0 0x0002D82D + 0x0002D82D 0x00080003 0x00080003 0x00006410 0x00000000 0x00000800 + + // dsc_decoder_frc: init 0 + 0x29 0x00 0x00 0x25 0x00F1 0x032 0x0001000C 0xF1311B8C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x600C6830 0x600CA005 + 0x9204A005 0xB2047602 0x6A692000 0x0C001400 0x04000800 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08074002 0xD4014002 0x9E027602 + 0xE49A2000 0x0C000800 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 1 + 0x29 0x01 0x00 0x25 0x00F1 0x032 0x0001000C 0xF1311C4C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x600C6830 0x600CA005 + 0x9204A005 0xB2047602 0x6A692000 0x0C001400 0x04000800 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08074002 0xD4014002 0x9E027602 + 0xE49A2000 0x0C000800 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 0 dual + 0x29 0x00 0x00 0x25 0x00F2 0x032 0x0001000C 0xF1311B8C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x600C6830 0x600CA005 + 0x9204A005 0xB2047602 0x6A692000 0x0C001400 0x04000800 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08070002 0xA0010002 0x77027602 + 0x91902000 0x0C000700 0x10000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 1 dual + 0x29 0x01 0x00 0x25 0x00F2 0x032 0x0001000C 0xF1311C4C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x600C6830 0x600CA005 + 0x9204A005 0xB2047602 0x6A692000 0x0C001400 0x04000800 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08070002 0xA0010002 0x77027602 + 0x91902000 0x0C000700 0x10000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_encoder_frc: init + 0x29 0x01 0x00 0x24 0x00F1 0x042 0x0001000C 0xF1311D0C + 0x00000003 0x00000002 0x01E001E0 0x000105A0 0x01E00125 0x00388EC0 + 0x0038D900 0x000E29E0 0xC0003000 0x01E005A0 0x00C000C0 0x00010240 + 0x00C00075 0x000CDAA0 0x000CF6C0 0x000336A8 0x00002000 0x00C00240 + 0x00000000 0x89000011 0x600C6830 0x600CA005 0x9204A005 0xB2047602 + 0x6A692000 0x0C001400 0x04000800 0xF1100018 0x00200C03 0x330B0B06 + 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 + 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF46B743B 0xAB000011 + 0x0807682C 0x08074002 0xD4014002 0x9E027602 0xE49A2000 0x0C000800 + 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 0x382A1C0E 0x69625446 + 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A 0xFA42FA42 0x784B3843 + 0xF653B64B 0x3464345C 0x34843484 0x00000004 + + // dsc_encoder_frc: init dual + 0x29 0x01 0x00 0x24 0x00F2 0x042 0x0001000C 0xF1311D0C + 0x00000003 0x00000002 0x01E001E0 0x000105A0 0x01E00125 0x00388EC0 + 0x0038D900 0x000E29E0 0xC0003000 0x01E005A0 0x00AB00AB 0x00010201 + 0x00AB0068 0x000B6D00 0x000B6D00 0x0002DB40 0x00002000 0x00AB0200 + 0x00000000 0x89000011 0x600C6830 0x600CA005 0x9204A005 0xB2047602 + 0x6A692000 0x0C001400 0x04000800 0xF1100018 0x00200C03 0x330B0B06 + 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 + 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF46B743B 0xAB000011 + 0x0807682C 0x08070002 0xA0010002 0x77027602 0x91902000 0x0C000700 + 0x10000E00 0xF1100018 0x00201007 0x330F0F06 0x382A1C0E 0x69625446 + 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A 0xFA42FA42 0x784B3843 + 0xF653B64B 0x3464345C 0x34843484 0x00000004 + + // blending: init + 0x29 0x00 0x00 0x2E 0x00F0 0x00B 0x0001000C 0xF1311E0C + 0x03E80081 0x0C6005A0 0x0C6005A0 0x0C6005A0 0x010004E7 0x000004E7 + 0x00000040 0x000004E7 0x00000001 + + // blending: init - continue + 0x29 0x01 0x00 0x2E 0x00F0 0x004 0x0001000C 0xF1311FE8 + 0x000400F0 0x000C00F0 + + // blending: init 2nd timing + 0x29 0x00 0x00 0x2E 0x00F1 0x00B 0x0001000C 0xF1311E0C + 0x03E80081 0x0C6005A0 0x0C6005A0 0x0C6005A0 0x010004E7 0x000004E7 + 0x00000040 0x000004E7 0x00000001 + + // blending: init 2nd timing - continue + 0x29 0x01 0x00 0x2E 0x00F1 0x004 0x0001000C 0xF1311FE8 + 0x000400F0 0x000C00F0 + + // blending: frc + 0x29 0x01 0x00 0x2E 0x0010 0x03 0x0001000C 0xF1311E24 + 0x000004E7 + + // blending: frc ocp + 0x29 0x01 0x00 0x2E 0x0011 0x03 0xFFFFFFF4 + 0xF1540018 0x000004E7 + + // blending: pt + 0x29 0x01 0x00 0x2E 0x0020 0x03 0x0001000C 0xF1311E24 + 0x00000040 + + // blending: pt ocp + 0x29 0x01 0x00 0x2E 0x0021 0x03 0xFFFFFFF4 + 0xF1540018 0x00000040 + + // blending: frc 2nd timing + 0x29 0x01 0x00 0x2E 0x0030 0x03 0x0001000C 0xF1311E24 + 0x000004E7 + + // blending: frc ocp 2nd timing + 0x29 0x01 0x00 0x2E 0x0031 0x03 0xFFFFFFF4 + 0xF1540018 0x000004E7 + + // dsc_decoder_aux: init + 0x29 0x01 0x00 0x37 0x00F0 0x01C 0x0001000C 0xF1311EEC + 0x00480150 0x01E001E0 0xAB000011 0x600CA030 0x1000A005 0x8403D002 + 0xFF1B9A01 0xD1011900 0x09000E00 0xD605CD04 0xEC100016 0x00201007 + 0x330F0F06 0x382A1C0E 0x69625446 0x7B797770 0x02027E7D 0x402A0022 + 0xFC3ABE32 0xF83AFA3A 0x783B383B 0xB64B763B 0xF44BB44B 0x347CF45B + 0x00000800 0x00000001 + + // bwosd init + 0x29 0x01 0x00 0x2C 0x00F0 0x03 0xFFFFFFF4 + 0xF17E0008 0x07800438 + + // osd_comp init + 0x29 0x01 0x00 0x2A 0x00F0 0x006 0x0001000C 0xF1311F54 + 0x0C6005A0 0x00000010 0x93070390 0x00000001 + + // pwil_v6 init + 0x29 0x01 0x00 0x23 0x00F0 0x01A 0x0001000C 0xF1311F64 + 0x00000001 0x00000024 0x00000000 0x0C6005A0 0x0710441E 0x00870010 + 0x00400000 0x038402D0 0x038402D0 0xE4D00010 0x00800AAA 0x00000000 + 0x0C6005A0 0x0C6005A0 0x00000010 0x00020000 0x00000000 0x0C6005A0 + 0x0C6005A0 0x00000000 0x0C5F0000 0x059F0000 0xA0800008 0x00000004 + + // pwil_v6 sw_rst + 0x29 0x01 0x00 0x23 0x00F1 0x03 0xFFFFFFF4 + 0xF1280000 0xA0800009 + + // mipi_rx_aux: dphy + 0x29 0x00 0x00 0x21 0x00F1 0x006 0x0001000C 0xF1311EBC + 0x0D020200 0x00000005 0x00004960 0x00000307 + + // mipi_rx_aux: dphy 2 + 0x29 0x01 0x00 0x21 0x00F1 0x006 0x0001000C 0xF1311FD8 + 0x00000307 0x00000307 0x00000307 0x00000304 + + // mipi_rx_aux: dphy 2nd timing + 0x29 0x00 0x00 0x21 0x00F2 0x006 0x0001000C 0xF1311EBC + 0x0D020200 0x00000005 0x00004960 0x00000307 + + // mipi_rx_aux: dphy 2 2nd timing + 0x29 0x01 0x00 0x21 0x00F2 0x006 0x0001000C 0xF1311FD8 + 0x00000307 0x00000307 0x00000307 0x00000304 + + + // mipi_rx_aux: ctrl + 0x29 0x01 0x00 0x21 0x00F0 0x00A 0x0001000C 0xF1311ECC + 0x00770000 0x059F0000 0x0C5F0000 0x00000780 0x01000000 0x001002D0 + 0x00000384 0x00000010 + + // bitmask pwil capen 0 + 0x29 0x01 0x00 0x03 0x0050 0x03 0xFFFFFFF4 + 0xF1240014 0x00000000 + + // bitmask pwil capen 1 + 0x29 0x01 0x00 0x03 0x0051 0x03 0x0001000C 0xF1311E34 + 0x00000001 + + // bitmask pwil capen 0 (dma) + 0x29 0x01 0x00 0x03 0x0052 0x03 0x0001000C 0xF1311E34 + 0x00000000 + + // bitmask pwil ad_frc + 0x29 0x01 0x00 0x03 0x0023 0x03 0x0001000C 0xF131067C + 0x05000008 + + // bitmask pwil fbo + 0x29 0x01 0x00 0x03 0x0022 0x03 0x0001000C 0xF1310718 + 0x00008200 + + // bitmask dpp cm cntl 2 + 0x29 0x01 0x00 0x0E 0x00FC 0x03 0x0001000C 0xF1310A04 + 0x0000006E + + // bitmask dpp cm cntl 3 + 0x29 0x01 0x00 0x0E 0x00FD 0x03 0x0001000C 0xF1310A00 + 0x00000100 + + // bitmask cm cntl + 0x29 0x01 0x00 0x0A 0x00FB 0x03 0x0001000C 0xF13107B0 + 0x0820E000 + + // bitmask cm magenta 6 + 0x29 0x01 0x00 0x0A 0x00B0 0x03 0x0001000C 0xF1310808 + 0x00A1B818 + + // bitmask cm red 6 + 0x29 0x01 0x00 0x0A 0x00B1 0x03 0x0001000C 0xF131080C + 0x00A1B816 + + // bitmask cm yellow 6 + 0x29 0x01 0x00 0x0A 0x00B2 0x03 0x0001000C 0xF1310810 + 0x00A1B812 + + // bitmask cm green 6 + 0x29 0x01 0x00 0x0A 0x00B3 0x03 0x0001000C 0xF1310814 + 0x00A1B81D + + // bitmask cm blue 6 + 0x29 0x01 0x00 0x0A 0x00B4 0x03 0x0001000C 0xF1310818 + 0x00A1B812 + + // bitmask cm cyan 6 + 0x29 0x01 0x00 0x0A 0x00B5 0x03 0x0001000C 0xF131081C + 0x00A1B823 + + // bitmask lce ahe_ctrl3 1 + 0x29 0x01 0x00 0x0D 0x00FD 0x03 0x0001000C 0xF1310C48 + 0x0F100100 + + // bitmask blc_pwm PWM_GEN_FREQ_SET + 0x29 0x01 0x00 0x06 0x00FD 0x03 0xFFFFFFF4 + 0xF10C0010 0x00000001 + + // bitmask dbc bl_user + 0x29 0x01 0x00 0x0F 0x00FD 0x03 0x0001000C 0xF131193C + 0x00000FFF + + // bitmask dbc led0d_gain + 0x29 0x01 0x00 0x0F 0x00FC 0x03 0x0001000C 0xF1311934 + 0x00000000 + + // bitmask sys pmu ctrl + 0x29 0x01 0x00 0x00 0x00F0 0x03 0xFFFFFFF4 + 0xF0000060 0x0F1BC146 + + // bitmask sys ulps ctrl + 0x29 0x01 0x00 0x00 0x00F1 0x03 0xFFFFFFF4 + 0xF00000C0 0x000001D5 + + // lk: dport: init + 0x29 0x00 0x00 0x04 0x00FA 0x0D 0xFFFFFFF4 + 0xF1220000 0xE0008007 0xF1220004 0x21000803 0xF1220008 0x4C6001C2 + 0xF122000C 0x46000800 0xF1220010 0x06081814 0xF1220014 0x00044100 + + // lk: dport: init + 0x29 0x01 0x00 0x04 0x00FA 0x03 0xFFFFFFF4 + 0xF1220028 0x00000000 + + // lk: dport: update + 0x29 0x01 0x00 0x04 0x008A 0x03 0xFFFFFFF4 + 0xF1220064 0x00000001 + + // lk: pwil: ctrl + 0x29 0x00 0x00 0x03 0x00FA 0x19 0xFFFFFFF4 + 0xF1240000 0xA0E82014 0xF1240004 0x00C8B794 0xF1240008 0x39020160 + 0xF124000C 0x50000016 0xF1240010 0x0C6005A0 0xF1240014 0x00000000 + 0xF1240018 0x038402D0 0xF124001C 0x038402D0 0xF1240038 0x00000080 + 0xF1240054 0x00000004 0xF1240078 0x0000001D 0xF124007C 0x0951094E + + // lk: pwil: ctrl + 0x29 0x01 0x00 0x03 0x00FA 0x07 0xFFFFFFF4 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + + // lk: pwil: update + 0x29 0x01 0x00 0x03 0x008A 0x03 0xFFFFFFF4 + 0x00000000 0x00000000 + + // lk: dsc_dec: init + 0x29 0x00 0x00 0x07 0x00FA 0x05 0xFFFFFFF4 + 0xF1680000 0x00480150 0xF1680004 0x01E001E0 + + // lk: dsc_dec: init pps + 0x29 0x01 0x00 0x07 0x00FA 0x2D 0xFFFFFFF4 + 0xF168000C 0xAB000011 0xF1680010 0x600CA030 0xF1680014 0x6000A005 + 0xF1680018 0x8403D002 0xF168001C 0xF0049A01 0xF1680020 0xBE091900 + 0xF1680024 0x0C000E00 0xF1680028 0xF9000301 0xF168002C 0xEC100016 + 0xF1680030 0x00201007 0xF1680034 0x330F0F06 0xF1680038 0x382A1C0E + 0xF168003C 0x69625446 0xF1680040 0x7B797770 0xF1680044 0xC2017E7D + 0xF1680048 0x402A0022 0xF168004C 0xFC3ABE32 0xF1680050 0xF83AFA3A + 0xF1680054 0x783B383B 0xF1680058 0xB64B763B 0xF168005C 0xF44BB44B + 0xF1680060 0x347CF45B + + // lk: dsc_dec: update + 0x29 0x01 0x00 0x07 0x008A 0x03 0xFFFFFFF4 + 0xF169FF00 0x00000001 + + // lk: dsc_enc: init + 0x29 0x00 0x00 0x08 0x00FA 0x05 0xFFFFFFF4 + 0xF1640000 0x00000003 0xF1640004 0x00000002 + + // lk: dsc_enc: init pps + 0x29 0x00 0x00 0x08 0x00FA 0x2D 0xFFFFFFF4 + 0xF1640008 0x00F001E0 0xF164000C 0x000202D0 0xF1640010 0x00F001C2 + 0xF1640014 0x00015180 0xF1640018 0x00015300 0xF164001C 0x0000A8C0 + 0xF1640020 0xC0002000 0xF1640024 0x00F002D0 0xF1640030 0x00F001E0 + 0xF1640034 0x000202D0 0xF1640038 0x00F001C2 0xF164003C 0x00015180 + 0xF1640040 0x00015300 0xF1640044 0x0000A8C0 0xF1640048 0x00002000 + 0xF164004C 0x00F002D0 0xF1640054 0x00000000 0xF1640064 0xAB000011 + 0xF1640068 0x600CA030 0xF164006C 0x6000A005 0xF1640070 0x8403D002 + 0xF1640074 0x20029A01 + + // lk: dsc_enc: init + 0x29 0x01 0x00 0x08 0x00FA 0x11 0xFFFFFFF4 + 0xF1640078 0xBE091900 0xF164007C 0x0C000E00 0xF1640080 0xF9000301 + 0xF1640084 0xEC100016 0xF1640088 0x00201007 0xF164008C 0x330F0F06 + 0xF1640090 0x382A1C0E 0xF1640094 0x69625446 + + // lk: dsc_enc: update + 0x29 0x01 0x00 0x08 0x008A 0x03 0xFFFFFFF4 + 0xF164009C 0xC2017E7D + + // lk: dpp: disable + 0x29 0x01 0x00 0x0E 0x00FA 0x05 0xFFFFFFF4 + 0xF1580014 0x0000001C 0xF1580290 0x00000002 + + // lk: peaking + 0x29 0x01 0x00 0x0C 0x00FA 0x07 0xFFFFFFF4 + 0xF1A0005C 0x000000F0 0xF1A00070 0x00000008 0xF1A00090 0x00000001 + + // lk: cm + 0x29 0x01 0x00 0x0A 0x00FA 0x05 0xFFFFFFF4 + 0xF1560118 0xFFFFFFFF 0xF1560160 0x00000001 + + // lk: scaler: init + 0x29 0x01 0x00 0x0B 0x00FA 0x23 0xFFFFFFF4 + 0xF1A20000 0x00026620 0xF1A20004 0x00000441 0xF1A20008 0x000E147A + 0xF1A2000C 0x000E147A 0xF1A20010 0x00006410 0xF1A20014 0x07080708 + 0xF1A20018 0x00000003 0xF1A2001C 0x00000003 0xF1A20020 0x00000000 + 0xF1A20024 0x0000001E 0xF1A20028 0x02400240 0xF1A2002C 0x00140000 + 0xF1A20030 0x00140000 0xF1A20034 0x00000003 0xF1A20038 0x00000003 + 0xF1A2003C 0x00006410 0xF1A20040 0x00000000 + + // lk: scaler: init dual + 0x29 0x01 0x00 0x0B 0x00FB 0x23 0xFFFFFFF4 + 0xF1A20000 0x00026620 0xF1A20004 0x00000441 0xF1A20008 0x000FD70A + 0xF1A2000C 0x000FD70A 0xF1A20010 0x00006410 0xF1A20014 0x06400640 + 0xF1A20018 0x00000003 0xF1A2001C 0x00000003 0xF1A20020 0x00000000 + 0xF1A20024 0x0000001E 0xF1A20028 0x02400240 0xF1A2002C 0x00140000 + 0xF1A20030 0x00140000 0xF1A20034 0x00000003 0xF1A20038 0x00000003 + 0xF1A2003C 0x00006410 0xF1A20040 0x00000000 + + // lk: scaler: gc + 0x29 0x01 0x00 0x0B 0x00AA 0x03 0xFFFFFFF4 + 0xF1A20044 0x00000800 + >; + + // for 1080x2376@60fps + pxlw,iris-cmd-list-1 = + < + // build : 03-03-2020 16:50 + // workbook: v0.69.1.u + // panel : v0p69p1pu_oneplus_fhd_dsc8_1080x2376_60fps_bpc8_bpp8_412p8_0303 + + // mipi_rx: dphy + 0x29 0x01 0x00 0x01 0x01F1 0x11 0xFFFFFFF4 + 0xF1800808 0x0D020200 0xF1800818 0x00000005 0xF1800A00 0x00004960 + 0xF1800A08 0x00000307 0xF1800A14 0x00000307 0xF1800A1C 0x00000307 + 0xF1800A24 0x00000307 0xF1800A2C 0x00000304 + + // mipi_rx: dphy 2nd timing + 0x29 0x01 0x00 0x01 0x01F2 0x11 0xFFFFFFF4 + 0xF1800808 0x0D020200 0xF1800818 0x00000005 0xF1800A00 0x00004960 + 0xF1800A08 0x00000307 0xF1800A14 0x00000307 0xF1800A1C 0x00000307 + 0xF1800A24 0x00000307 0xF1800A2C 0x00000304 + + // mipi_rx: ctrl + 0x29 0x01 0x00 0x01 0x00F0 0x13 0xFFFFFFF4 + 0xF1800238 0x00770000 0xF1800300 0x04370000 0xF1800304 0x09470000 + 0xF1801804 0x00000780 0xF1800104 0x01000000 0xF1800144 0x0048021C + 0xF1800148 0x0000021C 0xF1800080 0x00000110 0xF180001C 0x00000000 + + // mipi_rx: enter TTL bypass + 0x29 0x01 0x00 0x01 0x00D0 0x03 0xFFFFFFF4 + 0xF1800010 0x00200317 + + // mipi_rx: exit TTL bypass + 0x29 0x01 0x00 0x01 0x00D1 0x03 0xFFFFFFF4 + 0xF1800010 0x00200217 + + // mipi: abyp + 0x29 0x00 0x00 0x01 0x00E0 0x23 0x0001000C 0xF1311E38 + 0x0D020200 0x00000005 0x00004960 0x00000307 0x00770000 0x04370000 + 0x09470000 0x00000780 0x01000000 0x0048021C 0x0000021C 0x00000110 + 0x00004960 0x00410304 0x0000027F 0x3A040006 0x23082208 0x23081D07 + 0x00000201 0x034E0100 0x0068FB00 0x00FFFFFF 0x0A8C0780 0x00CB40C4 + 0x00000020 0x0048021C 0x0000021C 0x04370000 0x09470000 0x000000F1 + 0x01A30438 0xC201C139 0x00200217 + + // mipi: abyp + 0x29 0x01 0x00 0x01 0x00E0 0x07 0x0001000C 0xF1311FC4 + 0x00000307 0x00000307 0x00000307 0x00000304 0x00000000 + + // mipi: abyp 2nd timing + 0x29 0x00 0x00 0x01 0x00E1 0x23 0x0001000C 0xF1311E38 + 0x0D020200 0x00000005 0x00004960 0x00000307 0x00770000 0x04370000 + 0x09470000 0x00000780 0x01000000 0x0048021C 0x0000021C 0x00000110 + 0x00004960 0x00410304 0x0000027F 0x3A040006 0x23082208 0x23081D07 + 0x00000201 0x034E0100 0x00347D80 0x00FFFFFF 0x0A8C0780 0x00CB40C4 + 0x00000020 0x0048021C 0x0000021C 0x04370000 0x09470000 0x000000F1 + 0x01A30438 0xC201C139 0x00200217 + + // mipi: abyp 2nd timing + 0x29 0x01 0x00 0x01 0x00E1 0x07 0x0001000C 0xF1311FC4 + 0x00000307 0x00000307 0x00000307 0x00000304 0x00000000 + + // sys: a0: init 0 + 0x29 0x01 0x64 0x00 0x00A0 0x15 0xFFFFFFF4 + 0xF0000004 0x002A80AB 0xF0000008 0x0010F008 0xF0000020 0x002A80AA + 0xF0000024 0x0000F00E 0xF0000000 0x00000051 0xF0000000 0x00000052 + 0xF0000000 0x00000050 0xF000001C 0x00000081 0xF000001C 0x00000082 + 0xF000001C 0x00000080 + + // sys: a1: init 0 2nd timing + 0x29 0x01 0x64 0x00 0x00A1 0x15 0xFFFFFFF4 + 0xF0000004 0x002A80AB 0xF0000008 0x0010F008 0xF0000020 0x002A80AA + 0xF0000024 0x0000F00E 0xF0000000 0x00000051 0xF0000000 0x00000052 + 0xF0000000 0x00000050 0xF000001C 0x00000081 0xF000001C 0x00000082 + 0xF000001C 0x00000080 + + // sys: misc + 0x29 0x01 0x00 0x00 0x0000 0x15 0xFFFFFFF4 + 0xF000004C 0x0E109C20 0xF0000048 0x000032A0 0xF00000E0 0x00008180 + 0xF00000E4 0x0000D400 0xF0000060 0x0F1BC3C6 0xF00000C0 0x000001D5 + 0xF00000C4 0x000009EF 0xF0000088 0x0000001C 0xF00000F4 0x00000640 + 0xF00000D4 0x3F420303 + + // sys: abyp: enter + 0x29 0x01 0x00 0x00 0x0104 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000002 0xF00000EC 0x00000000 + + // sys: abyp: exit + 0x29 0x01 0x00 0x00 0x0105 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000001 0xF00000EC 0x00000000 + + // sys: pad select bitmask + 0x29 0x01 0x00 0x00 0x0006 0x03 0xFFFFFFF4 + 0xF00000E8 0x00000000 + + // sys: mem repair bitmask + 0x29 0x01 0x00 0x00 0x0007 0x03 0xFFFFFFF4 + 0xF00000F4 0x00000640 + + // sys: abyp: hs mode enter + 0x29 0x01 0x00 0x00 0x0008 0x05 0xFFFFFFF4 + 0xF00000EC 0x00000002 0xF00000EC 0x00000000 + + // sys: efuse for video abyp + 0x29 0x01 0x00 0x00 0x0010 0x05 0xFFFFFFF4 + 0xF0010004 0x03F000C0 0xF0010008 0x80000000 + + // sys: ungate clocks, power on PLLs + 0x29 0x01 0x00 0x00 0x0120 0x09 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000000 0x00000050 + 0xF000001C 0x00000080 + + // sys: switch clock mux back, power up domains + 0x29 0x01 0x00 0x00 0x0121 0x05 0xFFFFFFF4 + 0xF0000048 0x000032A0 0xF0000060 0x0F1BC3C6 + + // sys: power off domains, switch clock mux to XCLK + 0x29 0x01 0x00 0x00 0x0122 0x05 0xFFFFFFF4 + 0xF0000060 0x0F1BC006 0xF0000048 0x00002000 + + // sys: power off PLLs, gate clocks + 0x29 0x01 0x00 0x00 0x0123 0x09 0xFFFFFFF4 + 0xF000001C 0x00000084 0xF0000000 0x00000054 0xF0000050 0x0000CC26 + 0xF0000054 0x7A544004 + + // sys: ungate clocks, power on MIPI PLL + 0x29 0x01 0x00 0x00 0x0124 0x07 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF000001C 0x00000080 + + // sys: switch clock mux default + 0x29 0x01 0x00 0x00 0x0125 0x03 0xFFFFFFF4 + 0xF0000048 0x00004F60 + + // sys: switch clock mux to XCLK, power off MIPI PLL, gate clocks + 0x29 0x01 0x00 0x00 0x0126 0x09 0xFFFFFFF4 + 0xF0000048 0x00004000 0xF000001C 0x00000084 0xF0000050 0x0000CC26 + 0xF0000054 0x7A544004 + + // sys: ungate clocks, program PLLs + 0x29 0x01 0x64 0x00 0x0127 0x19 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000004 0x002A80AB + 0xF0000008 0x0010F008 0xF0000020 0x002A80AA 0xF0000024 0x0000F00E + 0xF0000000 0x00000051 0xF0000000 0x00000052 0xF0000000 0x00000050 + 0xF000001C 0x00000081 0xF000001C 0x00000082 0xF000001C 0x00000080 + + // sys: ungate clocks, program PLLs 2nd timing + 0x29 0x01 0x64 0x00 0x0128 0x19 0xFFFFFFF4 + 0xF0000050 0x00000000 0xF0000054 0x00000000 0xF0000004 0x002A80AB + 0xF0000008 0x0010F008 0xF0000020 0x002A80AA 0xF0000024 0x0000F00E + 0xF0000000 0x00000051 0xF0000000 0x00000052 0xF0000000 0x00000050 + 0xF000001C 0x00000081 0xF000001C 0x00000082 0xF000001C 0x00000080 + + // dtg: init + 0x29 0x01 0x00 0x05 0x0000 0x030 0x00000000 0xF1200000 + 0x00000003 0x00000003 0x0000010E 0x00000003 0x0000003C 0x000000EC + 0x00000948 0x00000DA5 0xA0914A53 0x800017AE 0x800017AE 0x00000008 + 0x00001740 0x00000000 0x00000000 0x00000000 0x00001726 0x0019B54D + 0x00000000 0x000030FC 0x000030FC 0x00000117 0x00000000 0x001A3EC0 + 0x00000000 0x00000000 0x00000000 0x00000000 0x10000101 0x00010001 + 0x800017AE 0x00199589 0x00199589 0x00000117 0x00000000 0x00000000 + 0x001A3EC0 0x001A2372 0x00000000 0x00000009 0x000002E9 0x00000101 + 0x0025C3F8 0x00000000 0x00000000 0x00000005 + + // dtg: init 2nd timing + 0x29 0x01 0x00 0x05 0x0001 0x30 0x00000000 0xF1200000 + 0x00000003 0x00000003 0x0000010E 0x00000003 0x0000003C 0x000000EC + 0x00000948 0x00000184 0xA0914A53 0x80000BBE 0x80000BBE 0x00000008 + 0x00000B4F 0x00000000 0x00000000 0x00000000 0x00000B35 0x000CB222 + 0x00000000 0x000018B4 0x000018B4 0x00000117 0x00000000 0x000D1F60 + 0x00000000 0x00000000 0x00000000 0x00000000 0x10000101 0x00010001 + 0x80000BBE 0x000C91E2 0x000C91E2 0x00000117 0x00000000 0x00000000 + 0x000D1F60 0x000CB222 0x00000000 0x00000009 0x00000168 0x00000101 + 0x0025C3F8 0x00000000 0x00000000 0x00000005 + + // dtg: update + 0x29 0x01 0x00 0x05 0x00F0 0x03 0xFFFFFFF4 + 0xF1210000 0x0000000F + + // mipi_tx: init + 0x29 0x01 0x00 0x02 0x0000 0x23 0xFFFFFFF4 + 0xF1880050 0x3A040006 0xF1880054 0x23082208 0xF1880058 0x23081D07 + 0xF1880004 0x00000201 0xF1880020 0x034E0100 0xF188002C 0x0068FB00 + 0xF1880030 0x00FFFFFF 0xF1880034 0x0A8C0780 0xF1880038 0x00CB40C4 + 0xF1880044 0x00000020 0xF1880010 0x0048021C 0xF1880014 0x0000021C + 0xF1880018 0x04370000 0xF188001C 0x09470000 0xF1880008 0x000000F1 + 0xF188000C 0x01A30438 0xF1880000 0xC201C139 + + // mipi_tx: init 2nd timing + 0x29 0x01 0x00 0x02 0x0004 0x23 0xFFFFFFF4 + 0xF1880050 0x3A040006 0xF1880054 0x23082208 0xF1880058 0x23081D07 + 0xF1880004 0x00000201 0xF1880020 0x034E0100 0xF188002C 0x00347D80 + 0xF1880030 0x00FFFFFF 0xF1880034 0x0A8C0780 0xF1880038 0x00CB40C4 + 0xF1880044 0x00000020 0xF1880010 0x0048021C 0xF1880014 0x0000021C + 0xF1880018 0x04370000 0xF188001C 0x09470000 0xF1880008 0x000000F1 + 0xF188000C 0x01A30438 0xF1880000 0xC201C139 + + // mipi_tx: dphy + 0x29 0x01 0x00 0x02 0x0001 0x07 0xFFFFFFF4 + 0xF18C0200 0x00004960 0xF18C0004 0x00410304 0xF18C0210 0x0000027F + + // mipi_tx: mode switch s3 + 0x29 0x01 0x00 0x02 0x0002 0x03 0xFFFFFFF4 + 0xF1880008 0x00000081 + + // mipi_tx: mode switch s5 + 0x29 0x01 0x00 0x02 0x0003 0x03 0xFFFFFFF4 + 0xF1880008 0x000000F1 + + // dport: init + 0x29 0x01 0x00 0x04 0x00F0 0x009 0x0001000C 0xF1311578 + 0xE0008007 0x21000803 0x4948010E 0x46000800 0x0608183C 0x00044100 + 0x00000000 + + // dport: update + 0x29 0x01 0x00 0x04 0x0080 0x003 0x0001000C 0xF1311594 + 0x00000001 + + // hdr: 0 + 0x29 0x01 0x00 0x09 0x0000 0x5E 0x0001000C 0xF1310FD8 + 0x0000016D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x04380948 0x00000068 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7E29 0x7FD77E8F 0x02000079 0x021A0200 0x00007F71 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x1D0E3617 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01100001 + + // hdr: 2 + 0x29 0x01 0x00 0x09 0x0002 0x5E 0x0001000C 0xF1310FD8 + 0x0000006D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x04380948 0x00000068 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x1D0E3617 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01100001 + + // hdr: 5 + 0x29 0x01 0x00 0x09 0x0005 0x5E 0x0001000C 0xF1310FD8 + 0x00001028 0x0FFF0000 0x0FFF0000 0x058F0124 0x00000804 0x0AE0023C + 0x00000FAD 0x00000011 0x0FFF082E 0x026600CC 0x002800CC 0x10080C06 + 0x20CC0F33 0x000AFFFF 0x00006461 0x00006461 0x00A30064 0x00A30064 + 0x04380948 0x00000068 0x0000020B 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x01790087 0x00120024 + 0x016F0005 0x001C0101 0x00000007 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0020E04A 0x003C9FC4 0x0017AF51 0x00408040 0x00000000 0x00000000 + 0x1C1C044E 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x0003FFFF 0x0003FFFF 0x00000000 0x00000000 0x07940708 + 0x00000000 0x01400001 + + // hdr: 9 + 0x29 0x01 0x00 0x09 0x0009 0x5E 0x0001000C 0xF1310FD8 + 0x0000006D 0x0FFF0000 0x0FFF0000 0x04E80273 0x0000075C 0x099804CB + 0x00000E65 0x0FFF082E 0x0FFF082E 0x099904CC 0x00000E66 0x00140A02 + 0x00000000 0x000000C8 0x00002828 0x00002828 0x02220028 0x02220028 + 0x04380948 0x00000068 0x00000100 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x018C0049 0x0000001E + 0x01750000 0x000E0151 0x00000002 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000004 0x08000800 0x00000800 + 0x0F0D7EAF 0x7B6E0BCC 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000008 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00040000 0x00000000 0x00040000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0015EB43 0x002FAED1 0x000FB947 0x00408040 0x00000000 0x00000003 + 0x110A3617 0x00140000 0x0007FFFF 0x00140001 0x00040000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x07940708 + 0x00000000 0x01100001 + + // hdr: c + 0x29 0x01 0x00 0x09 0x000C 0x5E 0x0001000C 0xF1310FD8 + 0x00001028 0x0FFF0000 0x0FFF0000 0x058F0124 0x00000804 0x0AE0023C + 0x00000FAD 0x00000011 0x0FFF082E 0x026600CC 0x002800CC 0x10080C06 + 0x20CC0F33 0x000AFFFF 0x00006461 0x00006461 0x00A30064 0x00A30064 + 0x04380948 0x00000068 0x0000020B 0x00000020 0x00000000 0x092C030D + 0x0FFF0DC4 0x1E061E06 0x1E061E06 0x00000008 0x01790087 0x00120024 + 0x016F0005 0x001C0101 0x00000007 0x00000000 0x00000000 0x00000000 + 0x00000009 0x056D7C52 0x7FAE7D1E 0x04000079 0x021A0400 0x00007EE2 + 0x00000000 0x00000000 0x00000000 0x00000004 0x08000800 0x00000800 + 0x0E2D7D3F 0x7A490B37 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000008 0x04B27CA7 0x7F597D5A 0x040000E9 0x02640400 0x00007EA6 + 0x00040000 0x00000000 0x00040000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x0020E04A 0x003C9FC4 0x0017AF51 0x00408040 0x00000000 0x00000000 + 0x1018044E 0x00140000 0x0007FFFF 0x00140000 0x00040000 0x00000000 + 0x00000000 0x0003FFFF 0x0003FFFF 0x00000001 0x00000001 0x07940708 + 0x00000000 0x01400001 + + // hdr: lut inv_u + 0x29 0x01 0x00 0x09 0x00FE 0x002 0x0001000C 0xF1311148 + + + // hdr: lut inv_v + 0x29 0x01 0x00 0x09 0x00FD 0x002 0x0001000C 0xF1311348 + + + // hdr: gc + 0x29 0x01 0x00 0x09 0x00A0 0x003 0x0001000C 0xF1311548 + 0x00000800 + + // hdr: update + 0x29 0x01 0x00 0x09 0x0080 0x003 0x0001000C 0xF1311574 + 0x00000002 + + // hdr: Y5P ctrl + 0x29 0x01 0x00 0x09 0x0090 0x03 0x0001000C 0xF1311144 + 0x01400001 + + // hdr: lut2 ctrl + 0x29 0x01 0x00 0x09 0x0091 0x03 0x0001000C 0xF131111C + 0x00140000 + + // hdr: luty ctrl + 0x29 0x01 0x00 0x09 0x0092 0x03 0x0001000C 0xF131102C + 0x00000020 + + // hdr: resolution + 0x29 0x01 0x00 0x09 0x0093 0x04 0x0001000C 0xF1311020 + 0x04380948 0x00000068 + + // hdr: ext 0 + 0x29 0x00 0x00 0x09 0x0070 0x003 0x00000000 0xF12D0028 + 0x10000000 + + // hdr: ext 1 + 0x29 0x01 0x00 0x09 0x0070 0x00B 0x00000000 0xF12D0004 + 0x1F7115F4 0x0AAA27E8 0x00000000 0x061E0294 0x0FFE0F80 0x061E0294 + 0x0FFE0F80 0x061E0294 0x0FFE0F80 + + // hdr: ext - dma + 0x29 0x01 0x00 0x09 0x0070 0x00C 0x0001000C 0xF131154C + 0x1F7115F4 0x0AAA27E8 0x00000000 0x061E0294 0x0FFE0F80 0x061E0294 + 0x0FFE0F80 0x061E0294 0x0FFE0F80 0x10000000 + + // pwil: ctrl 0 + 0x29 0x01 0x00 0x03 0x00F0 0x00B 0x0001000C 0xF1310608 + 0xA0E82014 0x00C8B794 0x38020060 0x50000012 0x09480438 0x00000000 + 0x021C021C 0x021C021C 0x00000080 + + // pwil: ctrl 1 + 0x29 0x01 0x00 0x03 0x00F1 0x006 0x0001000C 0xF1310608 + 0xA0E82014 0x00C8B794 0x38020060 0x50000012 + + // pwil: csc-0 (hdr) + 0x29 0x01 0x00 0x03 0x0090 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x09510951 0x00000951 0x11227E80 0x7ACC0D6E 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-1 (hdr) + 0x29 0x01 0x00 0x03 0x0091 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x095A095A 0x0014095A 0x051F7FEC 0x7EFC0104 0x00007D12 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-2 (hdr) + 0x29 0x01 0x00 0x03 0x0092 0x0B 0x0001000C 0xF1310630 + 0x0000001D 0x095A0000 0x00000000 0x09250000 0x00000925 0x00000000 + 0x00002000 0x00000000 0x00002000 + + // pwil: csc-3 (hdr) + 0x29 0x01 0x00 0x03 0x0093 0x0B 0x0001000C 0xF1310630 + 0x0000000F 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // pwil: csc-4 (hdr) + 0x29 0x01 0x00 0x03 0x0094 0x0B 0x0001000C 0xF1310630 + 0x00000011 0x09DC773A 0x090B04A8 0x13777E3B 0x013A090B 0x00007132 + 0x000FFB58 0x000FFB58 0x000FFB58 + + // pwil: csc-5 (frc) + 0x29 0x01 0x00 0x03 0x0095 0x0B 0x0001000C 0xF1310630 + 0x00000011 0x04B27CA7 0x7F597D5A 0x040000E9 0x02640400 0x00007EA6 + 0x00002000 0x00000000 0x00002000 + + // pwil: dpcd + 0x29 0x01 0x00 0x03 0x00F4 0x00C 0x0001000C 0xF1310654 + 0x00000000 0x00010000 0x00000200 0x00010001 0x00010001 0x000002D0 + 0x00000200 0x000004FC 0x00000000 0x05000000 + + // pwil: piad_info + 0x29 0x01 0x00 0x03 0x0020 0x004 0x0001000C 0xF131067C + 0x05000008 0x00000063 + + // pwil: ctrl graphic + 0x29 0x01 0x00 0x03 0x00A0 0x00C 0x0001000C 0xF1310684 + 0xE4100010 0x00030888 0x00000000 0x09480438 0x09480438 0x0000006E + 0x00040000 0x00000000 0x09480438 0x09480438 + + // pwil: ctrl graphic dual + 0x29 0x01 0x00 0x03 0x00A1 0x00C 0x0001000C 0xF1310684 + 0xE4100010 0x00030888 0x00000000 0x09480438 0x09480438 0x0000006E + 0x000B0000 0x00000000 0x09480438 0x09480438 + + // pwil: channel-order-0 + 0x29 0x01 0x00 0x03 0x0060 0x03 0x0001000C 0xF1310684 + 0xC9110010 + + // pwil: channel-order-1 + 0x29 0x01 0x00 0x03 0x0061 0x03 0x0001000C 0xF1310684 + 0xE4100010 + + // pwil: channel-order-2 + 0x29 0x01 0x00 0x03 0x0062 0x03 0x0001000C 0xF1310684 + 0xE4100010 + + // pwil: video + 0x29 0x01 0x00 0x03 0x00B0 0x00D 0x0001000C 0xF13106AC + 0xE4100030 0x00030888 0x92071B09 0x00000000 0x09480438 0x09480438 + 0x0000003B 0x00040000 0x00000000 0x09480438 0x07080240 + + // pwil: video dual + 0x29 0x01 0x00 0x03 0x00B1 0x00D 0x0001000C 0xF13106AC + 0xE4100030 0x00030888 0x92071B09 0x00000000 0x09480438 0x09480438 + 0x00000034 0x000B0000 0x00000000 0x09480438 0x07080200 + + // pwil: cursor + 0x29 0x01 0x00 0x03 0x00C0 0x00D 0x0001000C 0xF13106D8 + 0xE4D00010 0x00000888 0x00000000 0x09480438 0x09480438 0x00000010 + 0x00020000 0x00000000 0x00000000 0x00000000 0x09480438 + + // pwil: disp + 0x29 0x01 0x00 0x03 0x00D0 0x009 0x0001000C 0xF1310704 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00008200 + 0x00000000 + + // pwil: disp ctrl0 hw bitmask + 0x29 0x00 0x00 0x03 0x00D1 0x02 0x00000008 0xF12410B0 + 0x29 0x01 0x00 0x03 0x00D1 0x04 0x00000005 0xF12410B0 0x00000040 0x00000000 + + // pwil: frc + 0x29 0x01 0x00 0x03 0x00F2 0x009 0x0001000C 0xF1310720 + 0x09470000 0x04370000 0x00000003 0x00040000 0x00040000 0x00300000 + 0x00000000 + + // pwil: ad_blend + 0x29 0x01 0x00 0x03 0x00F3 0x03 0x0001000C 0xF1311E30 + 0x00000063 + + // pwil: pps sel + 0x29 0x01 0x00 0x03 0x0040 0x003 0x0001000C 0xF131062C + 0x00000004 + + // pwil: update + 0x29 0x01 0x00 0x03 0x0080 0x003 0x0001000C 0xF131073C + 0x00000100 + + // pwil: force update + 0x29 0x01 0x00 0x03 0x0030 0x03 0xFFFFFFF4 + 0xF1250000 0x00000200 + + // dpp: csc-0 + 0x29 0x01 0x00 0x0E 0x0040 0x0B 0x0001000C 0xF1310850 + 0x00000011 0x08000000 0x00000000 0x08000000 0x00000800 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: csc-1 + 0x29 0x01 0x00 0x0E 0x0041 0x0B 0x0001000C 0xF1310850 + 0x00000011 0x06A00000 0x00000000 0x06A00000 0x000006A0 0x00000000 + 0x0B000B00 0x00000B00 0x00000B00 + + // dpp: cm_csc-0 + 0x29 0x01 0x00 0x0E 0x0060 0x0B 0x0001000C 0xF1310A08 + 0x00000018 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: cm_csc-0 + 0x29 0x01 0x00 0x0E 0x0061 0x0B 0x0001000C 0xF1310A08 + 0x00000011 0x08880000 0x00000000 0x08880000 0x00000888 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // dpp: init + 0x29 0x01 0x00 0x0E 0x00F0 0x00C 0x0001000C 0xF131084C + 0x00010000 0x00000010 0x09510000 0x7FFE094E 0x10E47E4C 0x7BBD0E56 + 0x00000000 0x00000000 0x00000000 0x00000000 + + // dpp: init s curve + 0x29 0x01 0x00 0x0E 0x00F1 0x28 0x0001000C 0xF1310A2C + 0xB29500A4 0x80808080 0x00000002 0x00FFFFFF 0x00580800 0x006155E0 + 0x0066D648 0x006A568B 0x006CE6BC 0x006F46E3 0x00711703 0x0072B71E + 0x00742738 0x0075874C 0x0076B762 0x0077C773 0x0078C784 0x0079A792 + 0x007A97A1 0x007B67AF 0x000007BC 0x007C87C2 0x007D47CE 0x007DE7D9 + 0x007E97E3 0x007F27ED 0x007FC7F7 0x0080A801 0x00818811 0x0082381D + 0x0082A827 0x0082E82C 0x0082E82F 0x0082C82D 0x00824829 0x0081881F + 0x0080080E 0x00000800 + + // dpp: s curve level 0 + 0x29 0x01 0x00 0x0E 0x0070 0x24 0x0001000C 0xF1310A3C + 0x00713800 0x00727721 0x0072C72A 0x0073072F 0x00734732 0x00737735 + 0x0073C739 0x0074173F 0x00748744 0x0075074C 0x00758754 0x0076275D + 0x0076B767 0x00777771 0x0078477E 0x0079178A 0x00000797 0x007A679E + 0x007B57AD 0x007C47BD 0x007D57CC 0x007E67DD 0x007F87EF 0x0080A801 + 0x00818811 0x0082381D 0x0082A827 0x0082E82C 0x0082E82F 0x0082C82D + 0x00824829 0x0081881F 0x0080080E 0x00000800 + + // dpp: s curve level 1 + 0x29 0x01 0x00 0x0E 0x0071 0x24 0x0001000C 0xF1310A3C + 0x003E0800 0x0050B490 0x005BA568 0x006375FB 0x0069C66C 0x006F46CD + 0x0074271D 0x00784765 0x007C27A4 0x007FB7DE 0x00822810 0x00840831 + 0x0085784C 0x00868860 0x00876870 0x0088187C 0x00000885 0x0088A888 + 0x0088E88D 0x00890890 0x00890890 0x0088E88F 0x0088A88C 0x00885888 + 0x0087F882 0x0087687B 0x0086D872 0x0085285F 0x0083C846 0x0082B833 + 0x0081E824 0x00812818 0x0080080B 0x00000800 + + // dpp: s curve disable + 0x29 0x01 0x00 0x0E 0x0050 0x03 0x0001000C 0xF1310A2C + 0xB29500A4 + + // dpp: s curve enable + 0x29 0x01 0x00 0x0E 0x0051 0x03 0x0001000C 0xF1310A2C + 0xB29500A5 + + // dpp: gamma disable + 0x29 0x01 0x00 0x0E 0x0000 0x03 0x0001000C 0xF131084C + 0x00010000 + + // dpp: gamma enable + 0x29 0x01 0x00 0x0E 0x0001 0x03 0x0001000C 0xF131084C + 0x00010040 + + // dpp: gamma + 0x29 0x01 0x00 0x0E 0x00FE 0x002 0x0001000C 0xF1310874 + + + // dpp: dither + 0x29 0x01 0x00 0x0E 0x00F8 0x002 0x0001000C 0xF1310AC4 + + + // dpp: dpp_2 + 0x29 0x01 0x00 0x0E 0x00A0 0x003 0x0001000C 0xF1310BC4 + 0x00008100 + + // dpp: update + 0x29 0x01 0x00 0x0E 0x0080 0x003 0x0001000C 0xF1310BC8 + 0x00000001 + + // peaking2d: level0 + 0x29 0x01 0x00 0x0C 0x0000 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00200040 + 0x00000000 0x00000000 0x00FF00FF 0x00000000 0x00000000 0x000000E0 + + // peaking2d: level1 + 0x29 0x01 0x00 0x0C 0x0001 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00020002 0x00000000 + 0x03F40008 0x00200012 0x00020002 0x00000000 0x03F40008 0x00200012 + 0x00080008 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000000 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level2 + 0x29 0x01 0x00 0x0C 0x0002 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00040004 0x00000000 + 0x03F80010 0x00200012 0x00040004 0x00000000 0x03F80010 0x00200012 + 0x00100010 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level3 + 0x29 0x01 0x00 0x0C 0x0003 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00070007 0x00000000 + 0x03F70010 0x00200012 0x00070007 0x00000000 0x03F70010 0x00200012 + 0x00120012 0x00000000 0x03F80000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: level4 + 0x29 0x01 0x00 0x0C 0x0004 0x1A 0x0001000C 0xF1310740 + 0x00000000 0x00000000 0x03E00040 0x00600010 0x00090009 0x00000000 + 0x03F70010 0x00200012 0x00090009 0x00000000 0x03F70010 0x00200012 + 0x00140014 0x00000000 0x03F40000 0x00200008 0x00200040 0x00200040 + 0x00000000 0x00000001 0x00FF00FF 0x00FF0002 0x000003FF 0x000000E1 + + // peaking2d: csc 0 + 0x29 0x01 0x00 0x0C 0x0010 0x04 0x0001000C 0xF13107A0 + 0x00000009 0x00000009 + + // peaking2d: csc 1 + 0x29 0x01 0x00 0x0C 0x0011 0x04 0x0001000C 0xF13107A0 + 0x00000009 0x00000008 + + // peaking2d: init + 0x29 0x01 0x00 0x0C 0x00F0 0x01C 0x0001000C 0xF1310740 + 0x001E000A 0x0000000A 0x00E00020 0x025800A0 0x00780028 0x00000028 + 0x00E00020 0x032000A0 0x003C003C 0x00000014 0x00800000 0x03200078 + 0x003C003C 0x0000003C 0x00000000 0x03FC0000 0x00200040 0x00200040 + 0x00030000 0x00000000 0x00FF00FF 0x00FF0004 0x003F03FF 0x000000F0 + 0x00000000 0x00000000 + + // peaking2d: gc idle clk off + 0x29 0x01 0x00 0x0C 0x00A0 0x003 0x0001000C 0xF13107A8 + 0x00010800 + + // peaking2d: gc idle clk on + 0x29 0x01 0x00 0x0C 0x00A1 0x03 0x0001000C 0xF13107A8 + 0x00010803 + + // peaking2d: update + 0x29 0x01 0x00 0x0C 0x0080 0x003 0x0001000C 0xF13107AC + 0x00000001 + + // lce: level 0 + 0x29 0x01 0x00 0x0D 0x0000 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A5 0x00003C64 0x00201002 + + // lce: level 1 + 0x29 0x01 0x00 0x0D 0x0001 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 2 + 0x29 0x01 0x00 0x0D 0x0002 0x12 0x0001000C 0xF1310C3C + 0x028E1096 0x0A140000 0x002FFFFF 0x0E100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x00006446 0x0000280A 0x000FFC14 0x03FC0020 + 0x0080100A 0x000040A6 0x00003C64 0x000A0602 + + // lce: level 3 + 0x29 0x01 0x00 0x0D 0x0003 0x12 0x0001000C 0xF1310C3C + 0x010E1096 0x0A140000 0x002FFFFF 0x06100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x0000B464 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 4 + 0x29 0x01 0x00 0x0D 0x0004 0x12 0x0001000C 0xF1310C3C + 0x018E1096 0x0A140000 0x002FFFFF 0x10100258 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80096 0x0000B464 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00100802 + + // lce: level 5 + 0x29 0x01 0x00 0x0D 0x0005 0x12 0x0001000C 0xF1310C3C + 0x064E1096 0x0A140000 0x002FFFFF 0x191005DC 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C800C8 0x000168A5 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 6 + 0x29 0x01 0x00 0x0D 0x0006 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F44B1F4 0x00C80064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A5 0x00003C64 0x00201002 + + // lce: level 7 + 0x29 0x01 0x00 0x0D 0x0007 0x12 0x0001000C 0xF1310C3C + 0x014E1096 0x0A140000 0x002FFFFF 0x0F10012C 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000064 0x00004419 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 8 + 0x29 0x01 0x00 0x0D 0x0008 0x12 0x0001000C 0xF1310C3C + 0x028E1096 0x0A140000 0x002FFFFF 0x0610012C 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x00006446 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 9 + 0x29 0x01 0x00 0x0D 0x0009 0x12 0x0001000C 0xF1310C3C + 0x03CE1096 0x0A140000 0x002FFFFF 0x1E100384 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x0000B46E 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 10 + 0x29 0x01 0x00 0x0D 0x000A 0x12 0x0001000C 0xF1310C3C + 0x050E1096 0x0A140000 0x002FFFFF 0x1E1004B0 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x00000096 0x0001186E 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: level 11 + 0x29 0x01 0x00 0x0D 0x000B 0x12 0x0001000C 0xF1310C3C + 0x064E1096 0x0A140000 0x002FFFFF 0x1E1005DC 0x00001010 0x17C7D1F4 + 0x1F4029F4 0x000000C8 0x000168A5 0x0000280A 0x000FFC0A 0x03E80010 + 0x0080100A 0x000040A6 0x00003C64 0x00201002 + + // lce: gra_det 0 + 0x29 0x01 0x00 0x0D 0x0010 0x03 0x0001000C 0xF1310C7C + 0x2804003C + + // lce: gra_det 1 + 0x29 0x01 0x00 0x0D 0x0011 0x03 0x0001000C 0xF1310C7C + 0x2804083C + + // lce: reserved: TODO + 0x29 0x00 0x00 0x0D 0x00F0 0x003 0x0001000C 0xF1310C84 + 0xC77F0437 + + // lce: init + 0x29 0x01 0x00 0x0D 0x00F0 0x02F 0x0001000C 0xF1310BCC + 0x04370000 0x09470000 0x000191A0 0x000191A0 0x00018E40 0x00018E40 + 0x00018D12 0x000190C8 0x00018D12 0x00018DE8 0x00018A90 0x001DC0D8 + 0x00000100 0x001B00D8 0x00360288 0x003B81DC 0x00770594 0x00066667 + 0x00066667 0x00000412 0x00010453 0x00000419 0x00010625 0x00040000 + 0x00000000 0x00000F30 0x000006E7 0x000001A3 0x000E1096 0x0A140000 + 0x002FFFFF 0x0F100100 0x00001010 0x17C7D1F4 0x1F4029F4 0x00000096 + 0x00006464 0x0000280A 0x000FFC10 0x03E80010 0x0081100A 0x000040A5 + 0x00003C64 0x00201002 0x2804003C + + // lce: gc + 0x29 0x01 0x00 0x0D 0x00A0 0x003 0x0001000C 0xF1310C80 + 0x00000000 + + // lce: read + 0x29 0x01 0x00 0x0D 0x0070 0x0D4 0x0001000C 0xF1310C88 + 0x40000000 0x00000043 0x06010020 0x0C028080 0x120400E0 0x18058140 + 0x1E0701A0 0x24088200 0x2A0A0260 0x300B82C0 0x360D0320 0x3C0E8380 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x000003E0 0x01002000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + + // lce: update + 0x29 0x01 0x00 0x0D 0x0080 0x003 0x0001000C 0xF1310FD0 + 0x00000004 + + // lce: read update + 0x29 0x01 0x00 0x0D 0x0071 0x003 0x0001000C 0xF1310FD4 + 0x80000001 + + // cm: 6axis 0 + 0x29 0x01 0x00 0x0A 0x0000 0x04 0x0001000C 0xF13107B0 + 0x0820E000 0x03400010 + + // cm: 6axis 1 + 0x29 0x01 0x00 0x0A 0x0001 0x04 0x0001000C 0xF13107B0 + 0x0820E800 0x03000000 + + // cm: 6axis 2 + 0x29 0x01 0x00 0x0A 0x0002 0x04 0x0001000C 0xF13107B0 + 0x0820EC00 0x03000000 + + // cm: 6axis 3 + 0x29 0x01 0x00 0x0A 0x0003 0x04 0x0001000C 0xF13107B0 + 0x0820EFC0 0x03000000 + + // cm: color 0 + 0x29 0x01 0x00 0x0A 0x0020 0x08 0x0001000C 0xF13107F0 + 0x382A0C12 0x36280C1A 0x66510C0E 0x47390C12 0x120A0C36 0x55440C0E + + // cm: color 1 + 0x29 0x01 0x00 0x0A 0x0021 0x08 0x0001000C 0xF13107F0 + 0x382A0C12 0x500A2836 0x500A2836 0x500A2836 0x500A2836 0x55440C0E + + // cm: ftc 0 + 0x29 0x01 0x00 0x0A 0x0010 0x10 0x0001000C 0xF13107B8 + 0x7A067844 0x1C43FF10 0x15450018 0x00002215 0x3FE6B47F 0x00A05000 + 0x28ABF44B 0x7FF8103F 0x7840473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 1 + 0x29 0x01 0x00 0x0A 0x0011 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15450018 0x00282215 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80CBF 0x7840473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 2 + 0x29 0x01 0x00 0x0A 0x0012 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15280418 0x00201815 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80C3F 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 3 + 0x29 0x01 0x00 0x0A 0x0013 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15280418 0x002C1815 0x3FE6B47F 0x08C06018 + 0x2853F410 0x7FF80A3F 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: ftc 4 + 0x29 0x01 0x00 0x0A 0x0014 0x10 0x0001000C 0xF13107B8 + 0x7A06783D 0x0F43FF10 0x15450018 0x00282215 0x3FE6B47F 0x00C06018 + 0x2853F410 0x7FF80CBF 0xA040473A 0x005537B7 0x88034C40 0x708200D3 + 0x88034C40 0x70820384 + + // cm: csc 0 + 0x29 0x01 0x00 0x0A 0x0040 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0E307D40 0x7A480B38 0x00000000 + + // cm: csc 1 + 0x29 0x01 0x00 0x0A 0x0041 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x07177EA0 0x7D25059C 0x00000000 + + // cm: csc 2 + 0x29 0x01 0x00 0x0A 0x0045 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0F0D7EAF 0x7B6E0BCC 0x00000000 + + // cm: csc 3 + 0x29 0x01 0x00 0x0A 0x0046 0x08 0x0001000C 0xF1310820 + 0x00000019 0x08000800 0x00000800 0x0F0D7EAF 0x7B6E0BCC 0x00000000 + + // cm: init + 0x29 0x00 0x00 0x0A 0x00F0 0x012 0x0001000C 0xF13107B0 + 0x0820EFC0 0x13000000 0x7A067844 0x1C43FF10 0x15450018 0x002C2215 + 0x3FE6B47F 0x00A05000 0x28ABF44B 0x7FF8103F 0x7840473A 0x005537B7 + 0x88034C40 0x708200D3 0x88034C40 0x70820384 + + // cm: init csc + 0x29 0x01 0x00 0x0A 0x00F0 0x00B 0x0001000C 0xF1310820 + 0x0000001D 0x0951094E 0x7FFE094E 0x10E47E4C 0x7BBD0E56 0x00000000 + 0x00000000 0x00000000 0x00000000 + + // cm: gc + 0x29 0x01 0x00 0x0A 0x00A0 0x003 0x0001000C 0xF1310844 + 0x00000800 + + // cm: update + 0x29 0x01 0x00 0x0A 0x0080 0x003 0x0001000C 0xF1310848 + 0x00000100 + + // scaler1d + 0x29 0x01 0x00 0x0B 0x00F0 0x013 0x0001000C 0xF1311598 + 0x00026620 0x00000441 0x000A8F5C 0x000A8F5C 0x00006410 0x07080708 + 0x00010003 0x00010003 0x00000000 0x0000001E 0x02400240 0x000F0000 + 0x000F0000 0x00000003 0x00000003 0x00006410 0x00000000 + + // scaler1d dual + 0x29 0x01 0x00 0x0B 0x00F1 0x013 0x0001000C 0xF1311598 + 0x00026620 0x00000441 0x000A8F5C 0x000A8F5C 0x00006410 0x07080708 + 0x00010003 0x00010003 0x00000000 0x0000001E 0x02000200 0x0010E000 + 0x0010E000 0x00000003 0x00000003 0x00006410 0x00000000 + + // scaler1d: gc + 0x29 0x01 0x00 0x0B 0x00A0 0x003 0x0001000C 0xF13115DC + 0x00000800 + + // dbc: gc + 0x29 0x01 0x00 0x0F 0x00A0 0x003 0x0001000C 0xF1311748 + 0x00000800 + + // dbc: init + 0x29 0x00 0x00 0x0F 0x00F0 0x037 0x0001000C 0xF13118D0 + 0x50850421 0x00000000 0x00000000 0x0000003F 0x00000000 0x00000080 + 0x0000012C 0x00000400 0x00000600 0x00000E00 0x000002EC 0x00000400 + 0x00000448 0x00000197 0x000002C5 0x00000300 0x000000D6 0x00000067 + 0x00000009 0x00000043 0x00000026 0x00000004 0x00000140 0x000003CB + 0x000001B9 0x0000003F 0x00000002 0x00000FFF 0x000003CB 0x000001B9 + 0x00000000 0x0000000E 0x00000800 0x00000000 0x00000B38 0x00000800 + 0x00007D3E 0x00007A4A 0x00000800 0x00000E2C 0x00007FFE 0x00000800 + 0x00000000 0x00000B38 0x00000800 0x00007D3E 0x00007A4A 0x00000800 + 0x00000E2C 0x00007FFE 0x00000000 0x000003FF 0x00000FFF + + // dbc: init plcdcompw + 0x29 0x01 0x00 0x0F 0x00F0 0x023 0x0001000C 0xF131174C + 0x000003FF 0x000003E0 0x000003C0 0x000003A0 0x00000380 0x00000360 + 0x00000340 0x00000320 0x00000300 0x000002E6 0x000002CD 0x000002B3 + 0x0000029A 0x00000280 0x00000266 0x0000024D 0x00000233 0x0000021A + 0x00000200 0x000001E6 0x000001CD 0x000001B3 0x0000019A 0x00000180 + 0x00000166 0x0000013A 0x0000010D 0x000000E0 0x000000B3 0x00000087 + 0x0000005A 0x0000002D 0x00000000 + + // dbc: COREX0K0 + 0x29 0x01 0x00 0x0F 0x00FE 0x002 0x0001000C 0xF13117D0 + + + // dbc: read + 0x29 0x01 0x00 0x0F 0x0070 0x01A 0x0001000C 0xF13119A4 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000FFF 0x00000FFF + 0x00001000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x000003FF 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000063 0x00000000 0x00000FFF + + // dbc: off + 0x29 0x01 0x00 0x0F 0x0000 0x03 0x0001000C 0xF13118D0 + 0x40850423 + + // dbc: on + 0x29 0x01 0x00 0x0F 0x0001 0x03 0x0001000C 0xF13118D0 + 0x40840423 + + // dbc: level 0 + 0x29 0x01 0x00 0x0F 0x0010 0x04 0x0001000C 0xF1311934 + 0x00000000 0x00000000 + + // dbc: level 1 + 0x29 0x01 0x00 0x0F 0x0011 0x04 0x0001000C 0xF1311934 + 0x00000027 0x00000002 + + // dbc: level 2 + 0x29 0x01 0x00 0x0F 0x0012 0x04 0x0001000C 0xF1311934 + 0x00000022 0x00000002 + + // dbc: level 3 + 0x29 0x01 0x00 0x0F 0x0013 0x04 0x0001000C 0xF1311934 + 0x0000001B 0x00000002 + + // dbc: compenk table 0 + 0x29 0x01 0x00 0x0F 0x0020 0x03 0x0001000C 0xF13118D4 + 0x00000000 + + // dbc: compenk table 1 + 0x29 0x01 0x00 0x0F 0x0021 0x03 0x0001000C 0xF13118D4 + 0x00000001 + + // dbc: income table 0 + 0x29 0x01 0x00 0x0F 0x0030 0x03 0x0001000C 0xF13118D8 + 0x00000000 + + // dbc: income table 1 + 0x29 0x01 0x00 0x0F 0x0031 0x03 0x0001000C 0xF13118D8 + 0x00000001 + + // dbc: RGB in + 0x29 0x01 0x00 0x0F 0x0040 0x03 0x0001000C 0xF131194C + 0x00000006 + + // dbc: YUV in + 0x29 0x01 0x00 0x0F 0x0041 0x03 0x0001000C 0xF131194C + 0x00000007 + + // dsc_dec: init + 0x29 0x01 0x00 0x07 0x00F0 0x01A 0x0001000C 0xF13115E0 + 0x00480150 0x01E001E0 0x89000011 0x48098030 0x48003804 0x1C021C02 + 0x2A040002 0xFD062000 0x0C000700 0x6A015B01 0xF0100018 0x00200C03 + 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 + 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF463743B + + // dsc_dec: gc + 0x29 0x01 0x00 0x07 0x00A0 0x003 0x0001000C 0xF1311640 + 0x00000800 + + // dsc_dec: update + 0x29 0x01 0x00 0x07 0x0080 0x003 0x0001000C 0xF1311644 + 0x00000001 + + // dsc_enc: init + 0x29 0x01 0x00 0x08 0x00F0 0x042 0x0001000C 0xF1311648 + 0x00000003 0x00000002 0x00B40168 0x0002021C 0x00B4010E 0x000097E0 + 0x00009900 0x00004BF0 0xC0002000 0x00B4021C 0x00B40168 0x0002021C + 0x00B4010E 0x000097E0 0x00009900 0x00004BF0 0x00002000 0x00B4021C + 0x00000000 0x89000011 0x48098030 0x48003804 0x1C021C02 0x0E020002 + 0xFD062000 0x0C000700 0x6A015B01 0xF0100018 0x00200C03 0x330B0B06 + 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 + 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF463743B 0x89000011 + 0x48098030 0x48003804 0x1C021C02 0x0E020002 0xFD062000 0x0C000700 + 0x6A015B01 0xF0100018 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 + 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A + 0xF62AB61A 0x742B342B 0xF463743B 0x00000004 + + // dma: init + 0x29 0x01 0x00 0x11 0x00F0 0x15C 0x0001000C 0xF1310000 + 0x80080608 0xF1240000 0x80010628 0xF1240038 0x8001062C 0xF1240054 + 0x80090630 0xF1240078 0x800A0654 0xF12400A0 0x8001067C 0xF1240108 + 0x80010680 0xF1240120 0x800A0684 0xF1241000 0x800B06AC 0xF1241028 + 0x800B06D8 0xF1241084 0x80070704 0xF12410B4 0x80070720 0xF12410F0 + 0x8001073C 0xF1250000 0x80180740 0xF1A00000 0x800207A0 0xF1A0006C + 0x800107A8 0xF1A00060 0x800107AC 0xF1A00090 0x801007B0 0xF1560000 + 0x800107F0 0xF1560050 0x800107F4 0xF156006C 0x800107F8 0xF1560088 + 0x800107FC 0xF15600A4 0x80010800 0xF15600C0 0x80010804 0xF15600DC + 0x80010808 0xF1560058 0x8001080C 0xF1560074 0x80010810 0xF1560090 + 0x80010814 0xF15600AC 0x80010818 0xF15600C8 0x8001081C 0xF15600E4 + 0x80090820 0xF1560130 0x80010844 0xF1560118 0x80010848 0xF1560160 + 0x8001084C 0xF1580000 0x80090850 0xF1580014 0x80630874 0xF1580100 + 0x80020A00 0xF158003C 0x80090A08 0xF1580048 0x80030A2C 0xF158006C + 0x80010A38 0xF1580394 0x80220A3C 0xF1580078 0x80400AC4 0xF1580294 + 0x80010BC4 0xF1580008 0x80010BC8 0xF1580290 0x84020BCC 0xF1520064 + 0x840F0BD4 0xF1520094 0x840B0C10 0xF15200F8 0x84100C3C 0xF1520000 + 0x84010C7C 0xF1520054 0x84010C80 0xF1520058 0x84010C84 0xF1520070 + 0xC4D20C88 0xF1531008 0x84010FD0 0xF1531000 0xC4010FD4 0xF1531004 + 0x805C0FD8 0xF12C0000 0x81001148 0xF12C1400 0x80011548 0xF12CFF08 + 0xC00A154C 0xF12D0004 0x80011574 0xF12D0000 0x80061578 0xF1220000 + 0x80011590 0xF1220028 0x80011594 0xF1220064 0x80111598 0xF1A20000 + 0x800115DC 0xF1A20044 0x800215E0 0xF1680000 0x801615E8 0xF168000C + 0x80011640 0xF1680008 0x80011644 0xF169FF00 0x880A1648 0xF1640000 + 0x88081670 0xF1640030 0x88011690 0xF1640054 0x882D1694 0xF1640064 + 0x84011748 0xF1500404 0x8421174C 0xF1500178 0x844017D0 0xF1500304 + 0x840518D0 0xF1500000 0x841218E4 0xF1500014 0x8402192C 0xF1500080 + 0x84021934 0xF15000C8 0x8401193C 0xF15000DC 0x84021940 0xF1500100 + 0x84011948 0xF150015C 0x8413194C 0xF150040C 0x84031998 0xF1500458 + 0xC41819A4 0xF1518000 0x80031A04 0xF1400000 0x80011A10 0xF1400010 + 0xC0011A14 0xF1400010 0x80011A18 0xF140001C 0x80031A1C 0xF1400024 + 0x80011A28 0xF14000A8 0x80011A2C 0xF14000C8 0x80041A30 0xF1400104 + 0x80021A40 0xF140011C 0x80011A48 0xF141FF00 0x80011A4C 0xF17A0000 + 0x80011A50 0xF17BE000 0x0C191A54 0xF1720000 0x0C011AB8 0xF173FF00 + 0x0C0A1ABC 0xF1700000 0x0C011AE4 0xF1700054 0x0C161AE8 0xF1700064 + 0x0C011B40 0xF1700114 0x80121B44 0xF1A40000 0x8C2F1B8C 0xF16A0000 + 0x8C011C48 0xF16BFF00 0x8C2F1C4C 0xF16C0000 0x8C011D08 0xF16DFF00 + 0x8C0A1D0C 0xF1620000 0x8C081D34 0xF1620030 0x8C011D54 0xF1620054 + 0x8C2D1D58 0xF1620064 0x80071E0C 0xF1540000 0x80011E28 0xF1540060 + 0x80011E2C 0xF1550030 0x80011E30 0xF1240120 0x80011E34 0xF1240014 + 0x9C011E38 0xF1800808 0x9C011E3C 0xF1800818 0x9C011E40 0xF1800A00 + 0x9C011E44 0xF1800A08 0x9C011E48 0xF1800238 0x9C021E4C 0xF1800300 + 0x9C011E54 0xF1801804 0x9C011E58 0xF1800104 0x9C021E5C 0xF1800144 + 0x9C011E64 0xF1800080 0x9C011E68 0xF18C0200 0x9C011E6C 0xF18C0004 + 0x9C011E70 0xF18C0210 0x9C031E74 0xF1880050 0x9C011E80 0xF1880004 + 0x9C011E84 0xF1880020 0x9C041E88 0xF188002C 0x9C011E98 0xF1880044 + 0x9C041E9C 0xF1880010 0x9C021EAC 0xF1880008 0x9C011EB4 0xF1880000 + 0x9C011EB8 0xF1800010 0xB0011EBC 0xF1840808 0xB0011EC0 0xF1840818 + 0xB0011EC4 0xF1840A00 0xB0011EC8 0xF1840A08 0xB0011ECC 0xF1840238 + 0xB0011ED0 0xF1840300 0xB0011ED4 0xF1840304 0xB0011ED8 0xF1841804 + 0xB0011EDC 0xF1840104 0xB0021EE0 0xF1840144 0xB0011EE8 0xF1840080 + 0xB0021EEC 0xF16E0000 0xB0161EF4 0xF16E000C 0xB0011F4C 0xF16E0008 + 0xB0011F50 0xF16FFF00 0xB0031F54 0xF17C0000 0xB0011F60 0xF17D1000 + 0xB0061F64 0xF1280004 0xB0011F7C 0xF1280030 0xB0021F80 0xF1280038 + 0xB00D1F88 0xF1281000 0xB0011FBC 0xF1280000 0xB0011FC0 0xF1290000 + 0x9C011FC4 0xF1800A14 0x9C011FC8 0xF1800A1C 0x9C011FCC 0xF1800A24 + 0x9C011FD0 0xF1800A2C 0x9C011FD4 0xF180001C 0xB0011FD8 0xF1840A14 + 0xB0011FDC 0xF1840A1C 0xB0011FE0 0xF1840A24 0xB0011FE4 0xF1840A2C + 0x80011FE8 0xF1540030 0x80011FEC 0xF1540040 + + // dma: init no read + 0x29 0x01 0x00 0x11 0x00F1 0x15C 0x0001000C 0xF1310000 + 0x80080608 0xF1240000 0x80010628 0xF1240038 0x8001062C 0xF1240054 + 0x80090630 0xF1240078 0x800A0654 0xF12400A0 0x8001067C 0xF1240108 + 0x80010680 0xF1240120 0x800A0684 0xF1241000 0x800B06AC 0xF1241028 + 0x800B06D8 0xF1241084 0x80070704 0xF12410B4 0x80070720 0xF12410F0 + 0x8001073C 0xF1250000 0x80180740 0xF1A00000 0x800207A0 0xF1A0006C + 0x800107A8 0xF1A00060 0x800107AC 0xF1A00090 0x801007B0 0xF1560000 + 0x800107F0 0xF1560050 0x800107F4 0xF156006C 0x800107F8 0xF1560088 + 0x800107FC 0xF15600A4 0x80010800 0xF15600C0 0x80010804 0xF15600DC + 0x80010808 0xF1560058 0x8001080C 0xF1560074 0x80010810 0xF1560090 + 0x80010814 0xF15600AC 0x80010818 0xF15600C8 0x8001081C 0xF15600E4 + 0x80090820 0xF1560130 0x80010844 0xF1560118 0x80010848 0xF1560160 + 0x8001084C 0xF1580000 0x80090850 0xF1580014 0x80630874 0xF1580100 + 0x80020A00 0xF158003C 0x80090A08 0xF1580048 0x80030A2C 0xF158006C + 0x80010A38 0xF1580394 0x80220A3C 0xF1580078 0x80400AC4 0xF1580294 + 0x80010BC4 0xF1580008 0x80010BC8 0xF1580290 0x84020BCC 0xF1520064 + 0x840F0BD4 0xF1520094 0x840B0C10 0xF15200F8 0x84100C3C 0xF1520000 + 0x84010C7C 0xF1520054 0x84010C80 0xF1520058 0x84010C84 0xF1520070 + 0x44D20C88 0xF1531008 0x84010FD0 0xF1531000 0x44010FD4 0xF1531004 + 0x805C0FD8 0xF12C0000 0x81001148 0xF12C1400 0x80011548 0xF12CFF08 + 0x400A154C 0xF12D0004 0x80011574 0xF12D0000 0x80061578 0xF1220000 + 0x80011590 0xF1220028 0x80011594 0xF1220064 0x80111598 0xF1A20000 + 0x800115DC 0xF1A20044 0x800215E0 0xF1680000 0x801615E8 0xF168000C + 0x80011640 0xF1680008 0x80011644 0xF169FF00 0x880A1648 0xF1640000 + 0x88081670 0xF1640030 0x88011690 0xF1640054 0x882D1694 0xF1640064 + 0x84011748 0xF1500404 0x8421174C 0xF1500178 0x844017D0 0xF1500304 + 0x840518D0 0xF1500000 0x841218E4 0xF1500014 0x8402192C 0xF1500080 + 0x84021934 0xF15000C8 0x8401193C 0xF15000DC 0x84021940 0xF1500100 + 0x84011948 0xF150015C 0x8413194C 0xF150040C 0x84031998 0xF1500458 + 0x441819A4 0xF1518000 0x80031A04 0xF1400000 0x80011A10 0xF1400010 + 0x40011A14 0xF1400010 0x80011A18 0xF140001C 0x80031A1C 0xF1400024 + 0x80011A28 0xF14000A8 0x80011A2C 0xF14000C8 0x80041A30 0xF1400104 + 0x80021A40 0xF140011C 0x80011A48 0xF141FF00 0x80011A4C 0xF17A0000 + 0x80011A50 0xF17BE000 0x0C191A54 0xF1720000 0x0C011AB8 0xF173FF00 + 0x0C0A1ABC 0xF1700000 0x0C011AE4 0xF1700054 0x0C161AE8 0xF1700064 + 0x0C011B40 0xF1700114 0x80121B44 0xF1A40000 0x8C2F1B8C 0xF16A0000 + 0x8C011C48 0xF16BFF00 0x8C2F1C4C 0xF16C0000 0x8C011D08 0xF16DFF00 + 0x8C0A1D0C 0xF1620000 0x8C081D34 0xF1620030 0x8C011D54 0xF1620054 + 0x8C2D1D58 0xF1620064 0x80071E0C 0xF1540000 0x80011E28 0xF1540060 + 0x80011E2C 0xF1550030 0x80011E30 0xF1240120 0x80011E34 0xF1240014 + 0x9C011E38 0xF1800808 0x9C011E3C 0xF1800818 0x9C011E40 0xF1800A00 + 0x9C011E44 0xF1800A08 0x9C011E48 0xF1800238 0x9C021E4C 0xF1800300 + 0x9C011E54 0xF1801804 0x9C011E58 0xF1800104 0x9C021E5C 0xF1800144 + 0x9C011E64 0xF1800080 0x9C011E68 0xF18C0200 0x9C011E6C 0xF18C0004 + 0x9C011E70 0xF18C0210 0x9C031E74 0xF1880050 0x9C011E80 0xF1880004 + 0x9C011E84 0xF1880020 0x9C041E88 0xF188002C 0x9C011E98 0xF1880044 + 0x9C041E9C 0xF1880010 0x9C021EAC 0xF1880008 0x9C011EB4 0xF1880000 + 0x9C011EB8 0xF1800010 0xB0011EBC 0xF1840808 0xB0011EC0 0xF1840818 + 0xB0011EC4 0xF1840A00 0xB0011EC8 0xF1840A08 0xB0011ECC 0xF1840238 + 0xB0011ED0 0xF1840300 0xB0011ED4 0xF1840304 0xB0011ED8 0xF1841804 + 0xB0011EDC 0xF1840104 0xB0021EE0 0xF1840144 0xB0011EE8 0xF1840080 + 0xB0021EEC 0xF16E0000 0xB0161EF4 0xF16E000C 0xB0011F4C 0xF16E0008 + 0xB0011F50 0xF16FFF00 0xB0031F54 0xF17C0000 0xB0011F60 0xF17D1000 + 0xB0061F64 0xF1280004 0xB0011F7C 0xF1280030 0xB0021F80 0xF1280038 + 0xB00D1F88 0xF1281000 0xB0011FBC 0xF1280000 0xB0011FC0 0xF1290000 + 0x9C011FC4 0xF1800A14 0x9C011FC8 0xF1800A1C 0x9C011FCC 0xF1800A24 + 0x9C011FD0 0xF1800A2C 0x9C011FD4 0xF180001C 0xB0011FD8 0xF1840A14 + 0xB0011FDC 0xF1840A1C 0xB0011FE0 0xF1840A24 0xB0011FE4 0xF1840A2C + 0x80011FE8 0xF1540030 0x80011FEC 0xF1540040 + + // dma: init ctrl + 0x29 0x01 0x00 0x11 0x00E1 0x09 0xFFFFFFF4 + 0xF1300000 0x00000001 0xF1300004 0x00000000 0xF1300008 0x00AD0000 + 0xF1300004 0x0000000F + + // dma: write core + 0x29 0x01 0x00 0x11 0x00E2 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000001 + + // dma: write lce + 0x29 0x01 0x00 0x11 0x00E3 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000002 + + // dma: read core lce + 0x29 0x01 0x00 0x11 0x00E4 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00030000 + + // dma: write all + 0x29 0x01 0x00 0x11 0x00E5 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x0000000F + + // dma: write sw channel 8 + 0x29 0x01 0x00 0x11 0x00E6 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000100 + + // dma: write sw pq + 0x29 0x01 0x00 0x11 0x00E7 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00001000 + + // dma: write dsc + 0x29 0x01 0x00 0x11 0x00E8 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x00000008 + + // dma: abyp write + 0x29 0x01 0x00 0x11 0x01E9 0x05 0xFFFFFFF4 + 0xF1300004 0x00000000 0xF1300004 0x0000008F + + // blc_pwm: init + 0x29 0x01 0x00 0x06 0x00F0 0x03 0xFFFFFFF4 + 0xF10C0014 0x0001100A + + // blc_pwm: disable + 0x29 0x01 0x00 0x06 0x0000 0x03 0xFFFFFFF4 + 0xF10C0000 0x00001481 + + // blc_pwm: enable + 0x29 0x01 0x00 0x06 0x0001 0x03 0xFFFFFFF4 + 0xF10C0000 0x00001484 + + // psr_mif: init + 0x29 0x01 0x00 0x2D 0x00F0 0x014 0x0001000C 0xF1311A04 + 0x08E4CE14 0x14051085 0x48004C02 0x00004082 0x00004082 0x00100E20 + 0x00091000 0x000A1000 0x00200196 0x00004040 0x10410400 0x04380438 + 0x02400240 0x03700008 0x03700008 0x00020000 0x00000408 0x00000001 + + // psr_mif: init dual + 0x29 0x01 0x00 0x2D 0x00F1 0x014 0x0001000C 0xF1311A04 + 0x08E4CE14 0x1409D085 0x48004C02 0x00004082 0x00004082 0x00100E20 + 0x00091000 0x000B0000 0x00200196 0x00004040 0x10410400 0x04380438 + 0x02400240 0x03700008 0x03700008 0x00020000 0x00000408 0x00000001 + + // psr_mif: efifo_ctrl + 0x29 0x01 0x00 0x2D 0x00FD 0x03 0x0001000C 0xF1311A08 + 0x14051085 + + // psr_mif: efifo_ctrl dual + 0x29 0x01 0x00 0x2D 0x00FE 0x03 0x0001000C 0xF1311A08 + 0x1409D085 + + // osd_decomp: init + 0x29 0x01 0x00 0x2B 0x00F0 0x004 0x0001000C 0xF1311A4C + 0x00000473 0x00000100 + + // dsc_decoder_psr: init + 0x29 0x01 0x00 0x25 0x00F0 0x01C 0x0001000C 0xF1311A54 + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x48096830 0x48093804 + 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0x00000001 + + // dsc_encoder_psr: init + 0x29 0x01 0x00 0x24 0x00F0 0x024 0x0001000C 0xF1311ABC + 0x00000003 0x00000002 0x01680168 0x00010438 0x016800DC 0x001FD4F0 + 0x001FE780 0x0007F9E0 0xC0003000 0x01680438 0x00000000 0x89000011 + 0x48096830 0x48093804 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 + 0x06000B00 0xF1100018 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 + 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A + 0xF62AB61A 0x742B342B 0xF46B743B 0x00000004 + + // scaler_pp: init + 0x29 0x01 0x00 0x2F 0x00F0 0x014 0x0001000C 0xF1311B44 + 0x00026620 0x00000441 0x00060F83 0x00060F83 0x00006410 0x09480948 + 0x00030003 0x00030003 0x00000000 0x0000001E 0x04380438 0x00044444 + 0x00044444 0x00050003 0x00050003 0x00006410 0x00000000 0x00000800 + + // scaler_pp: init dual + 0x29 0x01 0x00 0x2F 0x00F1 0x014 0x0001000C 0xF1311B44 + 0x00026620 0x00000441 0x00060F83 0x00060F83 0x00006410 0x09480948 + 0x00030003 0x00030003 0x00000000 0x0000001E 0x04380438 0x0003CAE7 + 0x0003CAE7 0x00050003 0x00050003 0x00006410 0x00000000 0x00000800 + + // dsc_decoder_frc: init 0 + 0x29 0x00 0x00 0x25 0x00F1 0x032 0x0001000C 0xF1311B8C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x48096830 0x48093804 + 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08074002 0xD4014002 0x9E027602 + 0xE49A2000 0x0C000800 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 1 + 0x29 0x01 0x00 0x25 0x00F1 0x032 0x0001000C 0xF1311C4C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x48096830 0x48093804 + 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08074002 0xD4014002 0x9E027602 + 0xE49A2000 0x0C000800 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 0 dual + 0x29 0x00 0x00 0x25 0x00F2 0x032 0x0001000C 0xF1311B8C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x48096830 0x48093804 + 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08070002 0xA0010002 0x77027602 + 0x91902000 0x0C000700 0x10000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_decoder_frc: init 1 dual + 0x29 0x01 0x00 0x25 0x00F2 0x032 0x0001000C 0xF1311C4C + 0x00480158 0x03C003C0 0x00000800 0x89000011 0x48096830 0x48093804 + 0x6E033804 0xD4037602 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 + 0x00200C03 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D + 0x40090001 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B + 0xF46B743B 0xAB000011 0x0807682C 0x08070002 0xA0010002 0x77027602 + 0x91902000 0x0C000700 0x10000E00 0xF1100018 0x00201007 0x330F0F06 + 0x382A1C0E 0x69625446 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A + 0xFA42FA42 0x784B3843 0xF653B64B 0x3464345C 0x34843484 0x00000001 + + // dsc_encoder_frc: init + 0x29 0x01 0x00 0x24 0x00F1 0x042 0x0001000C 0xF1311D0C + 0x00000003 0x00000002 0x01680168 0x00010438 0x016800DC 0x001FD4F0 + 0x001FE780 0x0007F9E0 0xC0003000 0x01680438 0x00C000C0 0x00010240 + 0x00C00075 0x000CDAA0 0x000CF6C0 0x000336A8 0x00002000 0x00C00240 + 0x00000000 0x89000011 0x48096830 0x48093804 0x6E033804 0xD4037602 + 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 0x00200C03 0x330B0B06 + 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 + 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF46B743B 0xAB000011 + 0x0807682C 0x08074002 0xD4014002 0x9E027602 0xE49A2000 0x0C000800 + 0x0E000E00 0xF1100018 0x00201007 0x330F0F06 0x382A1C0E 0x69625446 + 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A 0xFA42FA42 0x784B3843 + 0xF653B64B 0x3464345C 0x34843484 0x00000004 + + // dsc_encoder_frc: init dual + 0x29 0x01 0x00 0x24 0x00F2 0x042 0x0001000C 0xF1311D0C + 0x00000003 0x00000002 0x01680168 0x00010438 0x016800DC 0x001FD4F0 + 0x001FE780 0x0007F9E0 0xC0003000 0x01680438 0x00AB00AB 0x00010201 + 0x00AB0068 0x000B6D00 0x000B6D00 0x0002DB40 0x00002000 0x00AB0200 + 0x00000000 0x89000011 0x48096830 0x48093804 0x6E033804 0xD4037602 + 0x1EFF2000 0x0C000F00 0x06000B00 0xF1100018 0x00200C03 0x330B0B06 + 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 0xFC19BE09 + 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF46B743B 0xAB000011 + 0x0807682C 0x08070002 0xA0010002 0x77027602 0x91902000 0x0C000700 + 0x10000E00 0xF1100018 0x00201007 0x330F0F06 0x382A1C0E 0x69625446 + 0x7B797770 0x80017D7C 0xBE323E22 0xFA3ABC3A 0xFA42FA42 0x784B3843 + 0xF653B64B 0x3464345C 0x34843484 0x00000004 + + // blending: init + 0x29 0x00 0x00 0x2E 0x00F0 0x00B 0x0001000C 0xF1311E0C + 0x03E80081 0x09480438 0x09480438 0x09480438 0x010005AE 0x000005AE + 0x00000031 0x000005AE 0x00000001 + + // blending: init - continue + 0x29 0x01 0x00 0x2E 0x00F0 0x004 0x0001000C 0xF1311FE8 + 0x000400F0 0x000C00F0 + + // blending: init 2nd timing + 0x29 0x00 0x00 0x2E 0x00F1 0x00B 0x0001000C 0xF1311E0C + 0x03E80081 0x09480438 0x09480438 0x09480438 0x010004CA 0x000004CA + 0x00000031 0x000004CA 0x00000001 + + // blending: init 2nd timing - continue + 0x29 0x01 0x00 0x2E 0x00F1 0x004 0x0001000C 0xF1311FE8 + 0x000400F0 0x000C00F0 + + // blending: frc + 0x29 0x01 0x00 0x2E 0x0010 0x03 0x0001000C 0xF1311E24 + 0x000005AE + + // blending: frc ocp + 0x29 0x01 0x00 0x2E 0x0011 0x03 0xFFFFFFF4 + 0xF1540018 0x000005AE + + // blending: pt + 0x29 0x01 0x00 0x2E 0x0020 0x03 0x0001000C 0xF1311E24 + 0x00000031 + + // blending: pt ocp + 0x29 0x01 0x00 0x2E 0x0021 0x03 0xFFFFFFF4 + 0xF1540018 0x00000031 + + // blending: frc 2nd timing + 0x29 0x01 0x00 0x2E 0x0030 0x03 0x0001000C 0xF1311E24 + 0x000004CA + + // blending: frc ocp 2nd timing + 0x29 0x01 0x00 0x2E 0x0031 0x03 0xFFFFFFF4 + 0xF1540018 0x000004CA + + // dsc_decoder_aux: init + 0x29 0x01 0x00 0x37 0x00F0 0x01C 0x0001000C 0xF1311EEC + 0x00480150 0x01E001E0 0x89000011 0x48098030 0x48003804 0x1C021C02 + 0x2A040002 0xFD062000 0x0C000700 0x6A015B01 0xF0100018 0x00200C03 + 0x330B0B06 0x382A1C0E 0x69625446 0x7B797770 0x02017E7D 0x40090001 + 0xFC19BE09 0xF819FA19 0x781A381A 0xF62AB61A 0x742B342B 0xF463743B + 0x00000800 0x00000001 + + // bwosd init + 0x29 0x01 0x00 0x2C 0x00F0 0x03 0xFFFFFFF4 + 0xF17E0008 0x07800438 + + // osd_comp init + 0x29 0x01 0x00 0x2A 0x00F0 0x006 0x0001000C 0xF1311F54 + 0x09480438 0x00000010 0x93070390 0x00000001 + + // pwil_v6 init + 0x29 0x01 0x00 0x23 0x00F0 0x01A 0x0001000C 0xF1311F64 + 0x00000001 0x00000020 0x00000000 0x09480438 0x0710441E 0x00870010 + 0x00400000 0x021C021C 0x021C021C 0xE4D00010 0x00800888 0x00000000 + 0x09480438 0x09480438 0x00000010 0x00020000 0x00000000 0x09480438 + 0x09480438 0x00000000 0x09470000 0x04370000 0xA0800008 0x00000004 + + // pwil_v6 sw_rst + 0x29 0x01 0x00 0x23 0x00F1 0x03 0xFFFFFFF4 + 0xF1280000 0xA0800009 + + // mipi_rx_aux: dphy + 0x29 0x00 0x00 0x21 0x00F1 0x006 0x0001000C 0xF1311EBC + 0x0D020200 0x00000005 0x00004960 0x00000307 + + // mipi_rx_aux: dphy 2 + 0x29 0x01 0x00 0x21 0x00F1 0x006 0x0001000C 0xF1311FD8 + 0x00000307 0x00000307 0x00000307 0x00000304 + + // mipi_rx_aux: dphy 2nd timing + 0x29 0x00 0x00 0x21 0x00F2 0x006 0x0001000C 0xF1311EBC + 0x0D020200 0x00000005 0x00004960 0x00000307 + + // mipi_rx_aux: dphy 2 2nd timing + 0x29 0x01 0x00 0x21 0x00F2 0x006 0x0001000C 0xF1311FD8 + 0x00000307 0x00000307 0x00000307 0x00000304 + + // mipi_rx_aux: ctrl + 0x29 0x01 0x00 0x21 0x00F0 0x00A 0x0001000C 0xF1311ECC + 0x00770000 0x04370000 0x09470000 0x00000780 0x01000000 0x0048021C + 0x0000021C 0x00000010 + + // bitmask pwil capen 0 + 0x29 0x01 0x00 0x03 0x0050 0x03 0xFFFFFFF4 + 0xF1240014 0x00000000 + + // bitmask pwil capen 1 + 0x29 0x01 0x00 0x03 0x0051 0x03 0x0001000C 0xF1311E34 + 0x00000001 + + // bitmask pwil capen 0 (dma) + 0x29 0x01 0x00 0x03 0x0052 0x03 0x0001000C 0xF1311E34 + 0x00000000 + + // bitmask pwil ad_frc + 0x29 0x01 0x00 0x03 0x0023 0x03 0x0001000C 0xF131067C + 0x05000008 + + // bitmask pwil fbo + 0x29 0x01 0x00 0x03 0x0022 0x03 0x0001000C 0xF1310718 + 0x00008200 + + // bitmask dpp cm cntl 2 + 0x29 0x01 0x00 0x0E 0x00FC 0x03 0x0001000C 0xF1310A04 + 0x0000006E + + // bitmask dpp cm cntl 3 + 0x29 0x01 0x00 0x0E 0x00FD 0x03 0x0001000C 0xF1310A00 + 0x00000100 + + // bitmask cm cntl + 0x29 0x01 0x00 0x0A 0x00FB 0x03 0x0001000C 0xF13107B0 + 0x0820E000 + + // bitmask cm magenta 6 + 0x29 0x01 0x00 0x0A 0x00B0 0x03 0x0001000C 0xF1310808 + 0x00A1B818 + + // bitmask cm red 6 + 0x29 0x01 0x00 0x0A 0x00B1 0x03 0x0001000C 0xF131080C + 0x00A1B816 + + // bitmask cm yellow 6 + 0x29 0x01 0x00 0x0A 0x00B2 0x03 0x0001000C 0xF1310810 + 0x00A1B812 + + // bitmask cm green 6 + 0x29 0x01 0x00 0x0A 0x00B3 0x03 0x0001000C 0xF1310814 + 0x00A1B81D + + // bitmask cm blue 6 + 0x29 0x01 0x00 0x0A 0x00B4 0x03 0x0001000C 0xF1310818 + 0x00A1B812 + + // bitmask cm cyan 6 + 0x29 0x01 0x00 0x0A 0x00B5 0x03 0x0001000C 0xF131081C + 0x00A1B823 + + // bitmask lce ahe_ctrl3 1 + 0x29 0x01 0x00 0x0D 0x00FD 0x03 0x0001000C 0xF1310C48 + 0x0F100100 + + // bitmask blc_pwm PWM_GEN_FREQ_SET + 0x29 0x01 0x00 0x06 0x00FD 0x03 0xFFFFFFF4 + 0xF10C0010 0x00000001 + + // bitmask dbc bl_user + 0x29 0x01 0x00 0x0F 0x00FD 0x03 0x0001000C 0xF131193C + 0x00000FFF + + // bitmask dbc led0d_gain + 0x29 0x01 0x00 0x0F 0x00FC 0x03 0x0001000C 0xF1311934 + 0x00000000 + + // bitmask sys pmu ctrl + 0x29 0x01 0x00 0x00 0x00F0 0x03 0xFFFFFFF4 + 0xF0000060 0x0F1BC146 + + // bitmask sys ulps ctrl + 0x29 0x01 0x00 0x00 0x00F1 0x03 0xFFFFFFF4 + 0xF00000C0 0x000001D5 + + // lk: dport: init + 0x29 0x00 0x00 0x04 0x00FA 0x0D 0xFFFFFFF4 + 0xF1220000 0xE0008007 0xF1220004 0x21000803 0xF1220008 0x4948010E + 0xF122000C 0x46000800 0xF1220010 0x0608183C 0xF1220014 0x00044100 + + // lk: dport: init + 0x29 0x01 0x00 0x04 0x00FA 0x03 0xFFFFFFF4 + 0xF1220028 0x00000000 + + // lk: dport: update + 0x29 0x01 0x00 0x04 0x008A 0x03 0xFFFFFFF4 + 0xF1220064 0x00000001 + + // lk: pwil: ctrl + 0x29 0x00 0x00 0x03 0x00FA 0x19 0xFFFFFFF4 + 0xF1240000 0xA0E82014 0xF1240004 0x00C8B794 0xF1240008 0x38020060 + 0xF124000C 0x50000012 0xF1240010 0x09480438 0xF1240014 0x00000000 + 0xF1240018 0x021C021C 0xF124001C 0x021C021C 0xF1240038 0x00000080 + 0xF1240054 0x00000004 0xF1240078 0x0000001D 0xF124007C 0x0951094E + + // lk: pwil: ctrl + 0x29 0x01 0x00 0x03 0x00FA 0x07 0xFFFFFFF4 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + + // lk: pwil: update + 0x29 0x01 0x00 0x03 0x008A 0x03 0xFFFFFFF4 + 0x00000000 0x00000000 + + // lk: dsc_dec: init + 0x29 0x00 0x00 0x07 0x00FA 0x05 0xFFFFFFF4 + 0xF1680000 0x00480150 0xF1680004 0x01E001E0 + + // lk: dsc_dec: init pps + 0x29 0x01 0x00 0x07 0x00FA 0x2D 0xFFFFFFF4 + 0xF168000C 0x89000011 0xF1680010 0x48098030 0xF1680014 0x48003804 + 0xF1680018 0x1C021C02 0xF168001C 0x2A040002 0xF1680020 0xFD062000 + 0xF1680024 0x0C000700 0xF1680028 0x6A015B01 0xF168002C 0xF0100018 + 0xF1680030 0x00200C03 0xF1680034 0x330B0B06 0xF1680038 0x382A1C0E + 0xF168003C 0x69625446 0xF1680040 0x7B797770 0xF1680044 0x02017E7D + 0xF1680048 0x40090001 0xF168004C 0xFC19BE09 0xF1680050 0xF819FA19 + 0xF1680054 0x781A381A 0xF1680058 0xF62AB61A 0xF168005C 0x742B342B + 0xF1680060 0xF463743B + + // lk: dsc_dec: update + 0x29 0x01 0x00 0x07 0x008A 0x03 0xFFFFFFF4 + 0xF169FF00 0x00000001 + + // lk: dsc_enc: init + 0x29 0x00 0x00 0x08 0x00FA 0x05 0xFFFFFFF4 + 0xF1640000 0x00000003 0xF1640004 0x00000002 + + // lk: dsc_enc: init pps + 0x29 0x00 0x00 0x08 0x00FA 0x2D 0xFFFFFFF4 + 0xF1640008 0x00B40168 0xF164000C 0x0002021C 0xF1640010 0x00B4010E + 0xF1640014 0x000097E0 0xF1640018 0x00009900 0xF164001C 0x00004BF0 + 0xF1640020 0xC0002000 0xF1640024 0x00B4021C 0xF1640030 0x00B40168 + 0xF1640034 0x0002021C 0xF1640038 0x00B4010E 0xF164003C 0x000097E0 + 0xF1640040 0x00009900 0xF1640044 0x00004BF0 0xF1640048 0x00002000 + 0xF164004C 0x00B4021C 0xF1640054 0x00000000 0xF1640064 0x89000011 + 0xF1640068 0x48098030 0xF164006C 0x48003804 0xF1640070 0x1C021C02 + 0xF1640074 0x0E020002 + + // lk: dsc_enc: init + 0x29 0x01 0x00 0x08 0x00FA 0x11 0xFFFFFFF4 + 0xF1640078 0xFD062000 0xF164007C 0x0C000700 0xF1640080 0x6A015B01 + 0xF1640084 0xF0100018 0xF1640088 0x00200C03 0xF164008C 0x330B0B06 + 0xF1640090 0x382A1C0E 0xF1640094 0x69625446 + + // lk: dsc_enc: update + 0x29 0x01 0x00 0x08 0x008A 0x03 0xFFFFFFF4 + 0xF164009C 0x02017E7D + + // lk: dpp: disable + 0x29 0x01 0x00 0x0E 0x00FA 0x05 0xFFFFFFF4 + 0xF1580014 0x0000001C 0xF1580290 0x00000002 + + // lk: peaking + 0x29 0x01 0x00 0x0C 0x00FA 0x07 0xFFFFFFF4 + 0xF1A0005C 0x000000F0 0xF1A00070 0x00000008 0xF1A00090 0x00000001 + + // lk: cm + 0x29 0x01 0x00 0x0A 0x00FA 0x05 0xFFFFFFF4 + 0xF1560118 0xFFFFFFFF 0xF1560160 0x00000001 + + // lk: scaler: init + 0x29 0x01 0x00 0x0B 0x00FA 0x23 0xFFFFFFF4 + 0xF1A20000 0x00026620 0xF1A20004 0x00000441 0xF1A20008 0x000A8F5C + 0xF1A2000C 0x000A8F5C 0xF1A20010 0x00006410 0xF1A20014 0x07080708 + 0xF1A20018 0x00010003 0xF1A2001C 0x00010003 0xF1A20020 0x00000000 + 0xF1A20024 0x0000001E 0xF1A20028 0x02400240 0xF1A2002C 0x000F0000 + 0xF1A20030 0x000F0000 0xF1A20034 0x00000003 0xF1A20038 0x00000003 + 0xF1A2003C 0x00006410 0xF1A20040 0x00000000 + + // lk: scaler: init dual + 0x29 0x01 0x00 0x0B 0x00FB 0x23 0xFFFFFFF4 + 0xF1A20000 0x00026620 0xF1A20004 0x00000441 0xF1A20008 0x000BE147 + 0xF1A2000C 0x000BE147 0xF1A20010 0x00006410 0xF1A20014 0x06400640 + 0xF1A20018 0x00010003 0xF1A2001C 0x00010003 0xF1A20020 0x00000000 + 0xF1A20024 0x0000001E 0xF1A20028 0x02400240 0xF1A2002C 0x000F0000 + 0xF1A20030 0x000F0000 0xF1A20034 0x00000003 0xF1A20038 0x00000003 + 0xF1A2003C 0x00006410 0xF1A20040 0x00000000 + + // lk: scaler: gc + 0x29 0x01 0x00 0x0B 0x00AA 0x03 0xFFFFFFF4 + 0xF1A20044 0x00000800 + >; + + }; +}; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5.dtsi b/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5.dtsi new file mode 100755 index 000000000000..4a73105e6a2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pxlw/pxlw-iris5.dtsi @@ -0,0 +1,162 @@ +/* Copyright (c) 2020, Pixelworks + * + * 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 "pxlw-iris5-cfg-samsung-wqhd-dsc8-90fps-cmd.dtsi" + +&tlmm { + pxlw_iris_gpio: pxlw_iris_gpio { + iris_reset_active: iris_reset_active { + mux { + pins = "gpio174"; + function = "gpio"; + }; + + config { + pins = "gpio174"; + drive-strength = <8>; /* 8 mA */ + bias-disable; + }; + }; + + iris_reset_suspend: iris_reset_suspend { + mux { + pins = "gpio174"; + function = "gpio"; + }; + + config { + pins = "gpio174"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + iris_wakeup_active: iris_wakeup_active { + mux { + pins = "gpio173"; + function = "gpio"; + }; + + config { + pins = "gpio173"; + drive-strength = <8>; + bias-disable; + }; + }; + + iris_wakeup_suspend: iris_wakeup_suspend { + mux { + pins = "gpio173"; + function = "gpio"; + }; + + config { + pins = "gpio173"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + iris_abyp_ready_active: iris_abyp_ready_active { + mux { + pins = "gpio112"; + function = "gpio"; + }; + + config { + pins = "gpio112"; + drive-strength = <8>; + bias-disable; + }; + }; + + iris_abyp_ready_suspend: iris_abyp_ready_suspend { + mux { + pins = "gpio112"; + function = "gpio"; + }; + + config { + pins = "gpio112"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + iris_vdd18_active: iris_vdd18_active { + mux { + pins = "gpio175"; + function = "gpio"; + }; + + config { + pins = "gpio175"; + drive-strength = <8>; + bias-pull-up; + }; + }; + + iris_vdd18_suspend: iris_vdd18_suspend { + mux { + pins = "gpio175"; + function = "gpio"; + }; + + config { + pins = "gpio175"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + +&soc { + dsi_iris_pwr_supply: dsi_iris_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "px_v18r"; + 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 = <0>; + }; + }; +}; + +&sde_dsi { + px_v18r-supply = <&pm8150_l7>; + pxlw,iris-lightup-config = <&mdss_iris_cfg_samsung_oneplus_dsc8_90fps_cmd>; +}; + +&sde_dsi1 { + px_v18r-supply = <&pm8150_l7>; +}; + +&vendor { + pxlw,iris { + compatible = "pxlw,iris"; + index = <0>; + + pinctrl-names = "iris_active", "iris_suspend"; + pinctrl-0 = <&iris_reset_active &iris_wakeup_active &iris_abyp_ready_active>; + pinctrl-1 = <&iris_reset_suspend &iris_wakeup_suspend &iris_abyp_ready_suspend>; + + qcom,iris-reset-gpio = <&tlmm 174 0>; + qcom,iris-wakeup-gpio = <&tlmm 173 0>; + qcom,iris-abyp-ready-gpio = <&tlmm 112 0>; + //qcom,iris-vdd-gpio = <&tlmm 175 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-1gb.dts new file mode 100644 index 000000000000..44e2065ac718 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-1gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 1Gb DDR HD+ SoC"; + compatible = "qcom,qcm4290"; + qcom,board-id = <0 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-2gb.dts new file mode 100644 index 000000000000..ff82989f2d22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-2gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 2Gb DDR HD+ SoC"; + compatible = "qcom,qcm4290"; + qcom,board-id = <0 0x403>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb-overlay.dts new file mode 100644 index 000000000000..6d954a69f117 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP 1Gb DDR HD+"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb.dts new file mode 100644 index 000000000000..9540a4fd3d05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-1gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP 1Gb DDR HD+"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,board-id = <34 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-2gb-overlay.dts new file mode 100644 index 000000000000..2c631196dad0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-2gb-overlay.dts @@ -0,0 +1,40 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP 2Gb DDR HD+"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "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/qcm4290-iot-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-2gb.dts new file mode 100644 index 000000000000..5872aeae98dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-2gb.dts @@ -0,0 +1,38 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP 2Gb DDR HD+"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "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/qcm4290-iot-idp-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-low-ram.dtsi new file mode 100644 index 000000000000..abbf5f8c9ccd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-low-ram.dtsi @@ -0,0 +1 @@ +#include "qcm4290-iot-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-overlay.dts new file mode 100644 index 000000000000..a7d76c0e6065 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IOT IDP Overlay"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb-overlay.dts new file mode 100644 index 000000000000..4ee851b3f2b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP AATC 1Gb DDR"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0x301>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb.dts new file mode 100644 index 000000000000..b9db41a43343 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-1gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP AATC 1Gb DDR"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,board-id = <34 0x301>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb-overlay.dts new file mode 100644 index 000000000000..8d5de8d654ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP AATC 2Gb DDR"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb.dts new file mode 100644 index 000000000000..52e95dc78f1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qcm4290-iot-low-ram.dtsi" +#include "qcm4290-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP AATC 2Gb DDR"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-overlay.dts new file mode 100644 index 000000000000..6fb910b1135e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcm4290-iot-idp.dtsi" +#include "qcm4290-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP USBC Audio"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc.dts new file mode 100644 index 000000000000..62b7adba5ccd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "qcm4290.dtsi" +#include "qcm4290-iot-idp.dtsi" +#include "qcm4290-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IDP USBC Audio"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp-usbc.dtsi new file mode 100644 index 000000000000..704385e62afe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-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/qcm4290-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp.dts new file mode 100644 index 000000000000..70472473a41d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qcm4290.dtsi" +#include "qcm4290-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 IOT IDP"; + compatible = "qcom,qcm4290-idp", "qcom,qcm4290", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp.dtsi new file mode 100644 index 000000000000..eef3e49bcece --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-idp.dtsi @@ -0,0 +1 @@ +#include "bengal-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-low-ram.dtsi new file mode 100644 index 000000000000..0c14224b9298 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290-iot-low-ram.dtsi @@ -0,0 +1,148 @@ +#include "qcm4290.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/qcm4290.dts b/arch/arm64/boot/dts/vendor/qcom/qcm4290.dts new file mode 100644 index 000000000000..165de35bbddd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "qcm4290.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290 SoC"; + compatible = "qcom,qcm4290"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcm4290.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcm4290.dtsi new file mode 100644 index 000000000000..f6fa09d30d69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcm4290.dtsi @@ -0,0 +1,8 @@ +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM4290"; + compatible = "qcom,qcm4290"; + qcom,msm-id = <469 0x0>; + qcom,msm-name = "QCM4290"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp-overlay.dts new file mode 100644 index 000000000000..618f69936c49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "qcs4290-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS4290 IOT IDP Overlay"; + compatible = "qcom,qcs4290-idp", "qcom,qcs4290", "qcom,idp"; + qcom,msm-id = <470 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dts new file mode 100644 index 000000000000..b356df9cd6f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qcs4290.dtsi" +#include "qcs4290-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS4290 IOT IDP"; + compatible = "qcom,qcs4290-idp", "qcom,qcs4290", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dtsi new file mode 100644 index 000000000000..eef3e49bcece --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcs4290-iot-idp.dtsi @@ -0,0 +1 @@ +#include "bengal-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/qcs4290.dts b/arch/arm64/boot/dts/vendor/qcom/qcs4290.dts new file mode 100644 index 000000000000..fa0ca0852626 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcs4290.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "qcs4290.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS4290 SoC"; + compatible = "qcom,qcs4290"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qcs4290.dtsi b/arch/arm64/boot/dts/vendor/qcom/qcs4290.dtsi new file mode 100644 index 000000000000..6691e41a0822 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qcs4290.dtsi @@ -0,0 +1,18 @@ +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS4290"; + compatible = "qcom,qcs4290"; + qcom,msm-id = <470 0x0>; + qcom,msm-name = "QCS4290"; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; 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 000000000000..051f64164fb2 --- /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 000000000000..389a2743a930 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl436186020H_3780mAh.dtsi @@ -0,0 +1,1040 @@ +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 450 10000000 + 451 550 1890000>; + + qcom,jeita-fv-ranges = <0 100 4400000 + 101 200 4400000 + 201 450 4400000 + 451 550 4050000>; + + qcom,step-chg-ranges = <3500000 4000000 10000000 + 4000001 4200000 8000000 + 4200001 4400000 6000000>; + 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 = <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 000000000000..456c17bc725c --- /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 000000000000..2acccf646547 --- /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 000000000000..3cfa38c0c168 --- /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 000000000000..a5ae2732a3ae --- /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 000000000000..0751a68fcc39 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-audio-overlay.dtsi @@ -0,0 +1,318 @@ +#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,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 3000000>; + 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 000000000000..bc1bbc6335a3 --- /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 000000000000..271d6b26b2ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-bus.dtsi @@ -0,0 +1,1002 @@ +#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,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_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 000000000000..bbcb275babfd --- /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 000000000000..34a178aaf977 --- /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 000000000000..fe56ba3c9cac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-gpu.dtsi @@ -0,0 +1,561 @@ +&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,bus-width = <32>; + 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 000000000000..6f364904b7aa --- /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 000000000000..3aea4f03e6da --- /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 000000000000..986c783d6ef5 --- /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 000000000000..6cfc22fc8455 --- /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 000000000000..dc18e1f0c56d --- /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 000000000000..5f3495c6da47 --- /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 000000000000..c9983ebaad5a --- /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 000000000000..5b4e4579c821 --- /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 000000000000..cba6f834d9d9 --- /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-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-low-ram.dtsi new file mode 100644 index 000000000000..8a6b97e58792 --- /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 000000000000..c38cae697d47 --- /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 000000000000..ee398146356c --- /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 000000000000..61c13bd3f61e --- /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 000000000000..a9ae201cf6c1 --- /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 000000000000..95fdb5c200d7 --- /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 000000000000..d3aed547800e --- /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 000000000000..ecb03db1025d --- /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 000000000000..f6df8604a5e0 --- /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 000000000000..6bf1d939e740 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd.dtsi @@ -0,0 +1,320 @@ +#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_gpu_trip: quiet-gpu-trip { + temperature = <43000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_cpu0_trip: quiet-cpu0-trip { + temperature = <41000>; + hysteresis = <0>; + 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 - 5)>; + }; + }; + }; +}; + +&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 000000000000..3c08b7908772 --- /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 000000000000..ad7cc634b0ad --- /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 = <3200000>; + 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 000000000000..9b225cfaca0b --- /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 000000000000..0562b208e012 --- /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 000000000000..8ccef0960719 --- /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 000000000000..b99826e92701 --- /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 = + <497016000 499086904 501157800 503228704>; + 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 000000000000..72e4bc6659e0 --- /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 000000000000..957b9bdb22a0 --- /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 000000000000..a17cdda96511 --- /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 000000000000..a2039b5bcb7e --- /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 000000000000..2d323c501050 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-thermal.dtsi @@ -0,0 +1,626 @@ +#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>; + }; +}; + +&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"; + }; + }; + }; + + gpu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 7>; + 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>; + }; + }; + }; + + 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 000000000000..819e7442f954 --- /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 000000000000..3e57fbbeec40 --- /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 000000000000..79e68912468f --- /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 000000000000..54892caef0e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba.dtsi @@ -0,0 +1,2664 @@ +#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>; + 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 */ + }; + + 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,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>; + 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,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>; + + 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>; + }; + }; + }; +}; + +&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>; +}; 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 000000000000..83bec4b37f12 --- /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 000000000000..98f61ac7c30f --- /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.dts b/arch/arm64/boot/dts/vendor/qcom/scubap.dts new file mode 100644 index 000000000000..16ebe7928265 --- /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/sdxprairie-thermal-integrated.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdxprairie-thermal-integrated.dtsi new file mode 100644 index 000000000000..1b44a62c7315 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdxprairie-thermal-integrated.dtsi @@ -0,0 +1,385 @@ +#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"; + }; + }; +}; + +&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"; + }; + }; + }; +}; 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 000000000000..a75e19fc6607 --- /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 000000000000..0996782681de --- /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 000000000000..91d172c35c35 --- /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/gki_defconfig b/arch/arm64/configs/gki_defconfig index 4e1ad9d96079..cda08acf09ee 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -374,6 +374,7 @@ CONFIG_DEVFREQ_GOV_PERFORMANCE=y CONFIG_DEVFREQ_GOV_POWERSAVE=y CONFIG_DEVFREQ_GOV_USERSPACE=y CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_PWM=y CONFIG_QCOM_PDC=y diff --git a/arch/arm64/configs/vendor/bengal-perf_defconfig b/arch/arm64/configs/vendor/bengal-perf_defconfig index 77f8b82398a2..da823d4be7d3 100644 --- a/arch/arm64/configs/vendor/bengal-perf_defconfig +++ b/arch/arm64/configs/vendor/bengal-perf_defconfig @@ -22,12 +22,14 @@ CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -92,6 +94,7 @@ CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y diff --git a/arch/arm64/configs/vendor/bengal_defconfig b/arch/arm64/configs/vendor/bengal_defconfig index cad29018fd58..431b8a27f603 100644 --- a/arch/arm64/configs/vendor/bengal_defconfig +++ b/arch/arm64/configs/vendor/bengal_defconfig @@ -22,6 +22,7 @@ CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -29,6 +30,7 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -97,6 +99,7 @@ CONFIG_KPROBES=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig index 0eb31fcab7ce..527e6534e01e 100644 --- a/arch/arm64/configs/vendor/kona-perf_defconfig +++ b/arch/arm64/configs/vendor/kona-perf_defconfig @@ -25,6 +25,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y +CONFIG_CGROUP_IOLIMIT=y # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -43,7 +44,7 @@ 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_HOTPLUG_SIZE_BITS is not set CONFIG_ARCH_QCOM=y CONFIG_ARCH_KONA=y CONFIG_PCI=y @@ -74,6 +75,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 @@ -104,10 +106,10 @@ 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_MEMORY_HOTPLUG is not set +# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set +# CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE is not set +# CONFIG_MEMORY_HOTREMOVE is not set CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_CMA_AREAS=16 @@ -338,6 +340,9 @@ CONFIG_CNSS_GENL=y CONFIG_NVM=y CONFIG_NVM_PBLK=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_FINGERPRINT=y +CONFIG_FINGERPRINT_GOODIX=y +CONFIG_FINGERPRINT_DETECT=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y @@ -361,6 +366,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y # CONFIG_DEVPORT is not set @@ -384,11 +390,16 @@ 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_QPNP_QNOVO5=y +CONFIG_ONEPLUS_WIRELESSCHG=y +CONFIG_ONEPLUS_FASTCHG=y +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_QPNP_QNOVO5=y CONFIG_QPNP_FG_GEN4=y -CONFIG_HL6111R=y +CONFIG_FG_BQ27541=y +CONFIG_CP_DA9313=y +CONFIG_CHGIC_MP2762=y +#CONFIG_HL6111R=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -565,8 +576,8 @@ 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_MEM_OFFLINE is not set +# CONFIG_OVERRIDE_MEMORY_LIMIT is not set CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_QBT_HANDLER=y CONFIG_QCOM_IPCC=y @@ -667,6 +678,9 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_F2FS_BD_STAT=y +CONFIG_F2FS_OF2FS=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y @@ -678,6 +692,8 @@ 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 @@ -713,6 +729,8 @@ CONFIG_SCHEDSTATS=y CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEFRAG=y +CONFIG_FSC=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y @@ -725,3 +743,51 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_OEM_FORCE_DUMP=y +CONFIG_PARAM_READ_WRITE=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_RF_CABLE_DETECT=y +CONFIG_PROJECT_INFO=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_VM_FRAGMENT_MONITOR=y +CONFIG_SENSOR_HALL_MXM1120=y +CONFIG_SENSOR_HALL_IST8801=y +CONFIG_TRI_STATE_KEY=y +CONFIG_HALL_TRI_STATE_KEY=y +CONFIG_IM=y +CONFIG_AW8697_HAPTIC=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_CRYPTO_LZ4=y +CONFIG_MEMPLUS=y +CONFIG_DIRECT_SWAPPINESS=y +CONFIG_ONEPLUS_MEM_MONITOR=y +CONFIG_ONEPLUS_FG_OPT=y +CONFIG_ONEPLUS_HEALTHINFO=y +CONFIG_CONTROL_CENTER=y +CONFIG_HOUSTON=y +CONFIG_UXCHAIN=y +#CONFIG_WB_KERNEL_LOG is not set +CONFIG_GPIO_SWITCH=y +CONFIG_REGULATOR_DEMO=y +CONFIG_REGULATOR_PM8008=y +CONFIG_SLA=y +CONFIG_SLA_ALGO=y +CONFIG_PCCORE=y +CONFIG_OPCHAIN=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_HUNG_TASK_ENHANCE=y +CONFIG_TPD=y diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig index 1502ee144e06..4c7338e7755a 100644 --- a/arch/arm64/configs/vendor/kona_defconfig +++ b/arch/arm64/configs/vendor/kona_defconfig @@ -27,6 +27,7 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y +CONFIG_CGROUP_IOLIMIT=y # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -43,7 +44,7 @@ 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_HOTPLUG_SIZE_BITS is not set CONFIG_ARCH_QCOM=y CONFIG_ARCH_KONA=y CONFIG_PCI=y @@ -76,6 +77,7 @@ CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y @@ -108,10 +110,10 @@ 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_MEMORY_HOTPLUG is not set +# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set +# CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE is not set +# CONFIG_MEMORY_HOTREMOVE is not set CONFIG_CLEANCACHE=y CONFIG_CMA=y CONFIG_CMA_DEBUG=y @@ -352,6 +354,9 @@ CONFIG_CNSS_GENL=y CONFIG_NVM=y CONFIG_NVM_PBLK=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_FINGERPRINT=y +CONFIG_FINGERPRINT_GOODIX=y +CONFIG_FINGERPRINT_DETECT=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y @@ -400,11 +405,16 @@ 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_QPNP_QNOVO5=y +CONFIG_ONEPLUS_WIRELESSCHG=y +CONFIG_ONEPLUS_FASTCHG=y +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_QPNP_QNOVO5=y CONFIG_QPNP_FG_GEN4=y -CONFIG_HL6111R=y +CONFIG_FG_BQ27541=y +CONFIG_CP_DA9313=y +CONFIG_CHGIC_MP2762=y +#CONFIG_HL6111R=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -590,8 +600,8 @@ 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_QCOM_MEM_OFFLINE is not set +# CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL is not set CONFIG_OVERRIDE_MEMORY_LIMIT=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_QBT_HANDLER=y @@ -699,6 +709,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 @@ -711,6 +723,8 @@ 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 @@ -759,7 +773,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 @@ -798,6 +812,8 @@ CONFIG_MEMTEST=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_DEFRAG=y +CONFIG_FSC=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_SOURCE_ETM4X=y @@ -810,3 +826,51 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_OEM_FORCE_DUMP=y +CONFIG_PARAM_READ_WRITE=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_RF_CABLE_DETECT=y +CONFIG_PROJECT_INFO=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_VM_FRAGMENT_MONITOR=y +CONFIG_SENSOR_HALL_MXM1120=y +CONFIG_SENSOR_HALL_IST8801=y +CONFIG_TRI_STATE_KEY=y +CONFIG_HALL_TRI_STATE_KEY=y +CONFIG_IM=y +CONFIG_AW8697_HAPTIC=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_CRYPTO_LZ4=y +CONFIG_MEMPLUS=y +CONFIG_DIRECT_SWAPPINESS=y +CONFIG_ONEPLUS_MEM_MONITOR=y +CONFIG_ONEPLUS_FG_OPT=y +CONFIG_ONEPLUS_HEALTHINFO=y +CONFIG_CONTROL_CENTER=y +CONFIG_HOUSTON=y +CONFIG_UXCHAIN=y +#CONFIG_WB_KERNEL_LOG is not set +CONFIG_GPIO_SWITCH=y +CONFIG_REGULATOR_DEMO=y +CONFIG_REGULATOR_PM8008=y +CONFIG_SLA=y +CONFIG_SLA_ALGO=y +CONFIG_PCCORE=y +CONFIG_OPCHAIN=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_HUNG_TASK_ENHANCE=y +CONFIG_TPD=y diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 957336254fc8..99562be0f197 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -41,7 +41,11 @@ * requires its definition to be available at this point in the inclusion * chain, and it may not be a power of 2 in the first place. */ +#if defined(CONFIG_MEMPLUS) && !(defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT)) +#define STRUCT_PAGE_MAX_SHIFT 7 +#else #define STRUCT_PAGE_MAX_SHIFT 6 +#endif /* * VMEMMAP_SIZE - allows the whole linear region to be covered by diff --git a/arch/arm64/include/uapi/asm/setup.h b/arch/arm64/include/uapi/asm/setup.h index 5d703888f351..9f583cb9e76e 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/perf_event.c b/arch/arm64/kernel/perf_event.c index c1bb288abcd6..606ebcd89ffd 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 73d5ac36803d..eec0670355ad 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -101,8 +101,8 @@ 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, - jiffies_to_msecs(jiffies - start)); + //pr_info("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 ece9ee623a88..0fd3312755c2 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. @@ -527,9 +530,15 @@ retry: * the mmap_sem because it would already be released * in __lock_page_or_retry in mm/filemap.c. */ +#ifdef CONFIG_MEMPLUS + count_vm_event(RETRYPAGE); +#endif 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 +601,9 @@ done: * oom-killed). */ pagefault_out_of_memory(); +#ifdef CONFIG_CGROUP_IOLIMIT + task_clear_in_pagefault(tsk); +#endif return 0; } @@ -626,10 +638,16 @@ done: } __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 157f2caa1351..4b2dde7d6d3b 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 f61a9f139cf8..7e50d91c3661 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 256fa1ccc2bd..5fa1d2f6b757 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 1a5b67b57e6b..0a1cc09723b8 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 2b2a936cf848..e10af20eb90c 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 b37e4b5566cb..98334cad7f3d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -230,4 +230,6 @@ 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 9a258f18ec6f..69ffa981050a 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 e9407d3aadf8..6b6ecbee1f47 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -77,10 +77,16 @@ #include +#include + #include "binder_alloc.h" #include "binder_internal.h" #include "binder_trace.h" +#ifdef CONFIG_OP_FREEZER +#include +#endif + static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); @@ -1161,6 +1167,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 +2901,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 +2998,13 @@ 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 + 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 +3120,19 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_dead_binder; } + +#ifdef CONFIG_OP_FREEZER + if (!(tr->flags & TF_ONE_WAY) + && 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 +3365,35 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_bad_offset; } + +#ifdef CONFIG_OP_FREEZER + if ((tr->flags & TF_ONE_WAY) + && 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, (void __user *)tr->data.ptr.buffer, buf_data_size)) { + 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 +3401,10 @@ 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 + 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 +3594,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 +4264,13 @@ 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 + current->in_binder = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 +4563,18 @@ retry: 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; } @@ -5993,6 +6092,69 @@ int binder_state_show(struct seq_file *m, void *unused) return 0; } +#ifdef CONFIG_OP_FREEZER +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 deb37977cab9..11c05ca4fb00 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -33,6 +33,12 @@ #include #include "binder_alloc.h" #include "binder_trace.h" +#ifdef CONFIG_OPCHAIN +#include +#endif +#ifdef CONFIG_OP_FREEZER +#include +#endif struct list_lru binder_alloc_lru; @@ -362,6 +368,9 @@ 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 + struct task_struct *p = NULL; +#endif if (!binder_alloc_get_vma(alloc)) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, @@ -386,6 +395,22 @@ static struct binder_buffer *binder_alloc_new_buf_locked( alloc->pid, extra_buffers_size); return ERR_PTR(-EINVAL); } + +#ifdef CONFIG_OP_FREEZER + 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 +1159,22 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, } return 0; } +#ifdef 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 b60d161b7a7a..1fc559b57726 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -160,7 +160,11 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc) mutex_unlock(&alloc->mutex); return free_async_space; } - +#ifdef 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, struct binder_buffer *buffer, diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 5d73ab6b62e1..1b5caf34a2ba 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -329,6 +329,10 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) break; } + if (!strcmp(fw_priv->fw_name, "iris5_ccf1b.fw") || + !strcmp(fw_priv->fw_name, "iris5_ccf2b.fw")) + snprintf(path, PATH_MAX, "%s/%s", "/data/vendor/display", fw_priv->fw_name); + fw_priv->size = 0; rc = kernel_read_file_from_path(path, &fw_priv->data, &size, msize, id); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 5ad1ebf794b2..5610ae2c403f 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" @@ -76,6 +78,10 @@ static struct wakeup_source deleted_ws = { .lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock), }; +#define WORK_TIMEOUT (60*1000) +static void ws_printk(struct work_struct *work); +static DECLARE_DELAYED_WORK(ws_printk_work, ws_printk); + static DEFINE_IDA(wakeup_ida); /** @@ -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/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 54b09bfac5da..920fb7c4eda8 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -36,6 +36,7 @@ #define BT_PWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg) #define BT_PWR_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) +#define SW_CTRL_GPIO_MAX_RETRY_TIMES 5 static const struct of_device_id bt_power_match_table[] = { { .compatible = "qca,ar3002" }, @@ -53,6 +54,7 @@ static int pwr_state; struct class *bt_class; static int bt_major; static int soc_id; +static int sw_ctl_pin_rety_cnt; static int bt_vreg_init(struct bt_power_vreg_data *vreg) { @@ -319,6 +321,40 @@ static int bt_configure_gpios(int on) bt_sw_ctrl_gpio, gpio_get_value(bt_sw_ctrl_gpio)); } + + while ((gpio_get_value(bt_sw_ctrl_gpio) == 0) && (sw_ctl_pin_rety_cnt > 0)) { + sw_ctl_pin_rety_cnt--; + BT_PWR_INFO("BTON:bt-sw-ctrol-gpio is 0, retry %d", + SW_CTRL_GPIO_MAX_RETRY_TIMES - sw_ctl_pin_rety_cnt); + + rc = gpio_direction_output(bt_reset_gpio, 0); + if (rc) { + BT_PWR_ERR("Unable to set direction to 0\n"); + return rc; + } + msleep(50); + BT_PWR_INFO("BTON:Switch reset pin to low, bt-reset-gpio(%d) value(%d)\n", + bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { + BT_PWR_INFO("State: bt-sw-ctrl-gpio(%d) value(%d)", + bt_sw_ctrl_gpio, + gpio_get_value(bt_sw_ctrl_gpio)); + } + + rc = gpio_direction_output(bt_reset_gpio, 1); + if (rc) { + BT_PWR_ERR("Unable to set direction to 1\n"); + return rc; + } + msleep(50); + BT_PWR_INFO("BTON:Switch reset pin to hight, bt-reset-gpio(%d) value(%d)\n", + bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { + BT_PWR_INFO("State: bt-sw-ctrl-gpio(%d) value(%d)", + bt_sw_ctrl_gpio, + gpio_get_value(bt_sw_ctrl_gpio)); + } + } } else { gpio_set_value(bt_reset_gpio, 0); if (bt_debug_gpio >= 0) @@ -434,6 +470,7 @@ static int bluetooth_power(int on) } } if (bt_power_pdata->bt_gpio_sys_rst > 0) { + sw_ctl_pin_rety_cnt = SW_CTRL_GPIO_MAX_RETRY_TIMES; rc = bt_configure_gpios(on); if (rc < 0) { BT_PWR_ERR("bt_power gpio config failed"); diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index ce4a33bcc8f2..68ff8cce3310 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -49,8 +49,8 @@ enum MHI_DEBUG_LEVEL mhi_ipc_log_lvl = MHI_MSG_LVL_VERBOSE; #else -#define MHI_IPC_LOG_PAGES (10) -#define MHI_CNTRL_LOG_PAGES (5) +#define MHI_IPC_LOG_PAGES (100) +#define MHI_CNTRL_LOG_PAGES (25) enum MHI_DEBUG_LEVEL mhi_ipc_log_lvl = MHI_MSG_LVL_ERROR; #endif @@ -399,7 +399,7 @@ static int mhi_bl_probe(struct mhi_device *mhi_device, snprintf(node_name, sizeof(node_name), "mhi_bl_%04x_%02u.%02u.%02u", mhi_device->dev_id, mhi_device->domain, mhi_device->bus, mhi_device->slot); - + MHI_ERR("mhi_ipc %s", node_name); arch_info->boot_dev = mhi_device; arch_info->boot_ipc_log = ipc_log_context_create(MHI_CNTRL_LOG_PAGES, node_name, 0); @@ -453,7 +453,7 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) mhi_cntrl->slot); mhi_cntrl->log_buf = ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0); - mhi_cntrl->log_lvl = mhi_ipc_log_lvl; + mhi_cntrl->log_lvl = MHI_MSG_LVL_VERBOSE; snprintf(node, sizeof(node), "mhi_cntrl_%04x_%02u.%02u.%02u", mhi_cntrl->dev_id, mhi_cntrl->domain, mhi_cntrl->bus, diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 692cb2dff60c..4a0f888e7804 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -18,7 +18,7 @@ #include "mhi_internal.h" static void mhi_process_sfr(struct mhi_controller *mhi_cntrl, - struct file_info *info) + struct file_info *info, char *buf, size_t len) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; u8 *sfr_buf, *file_offset = info->file_offset; @@ -59,6 +59,10 @@ static void mhi_process_sfr(struct mhi_controller *mhi_cntrl, /* force sfr string to log in kernel msg */ MHI_ERR("%s\n", sfr_buf); + + /* return sfr string for subsystem crash reason */ + if (info->file_size < SFR_BUF_SIZE) + strlcpy(buf, sfr_buf, info->file_size); err: kfree(sfr_buf); } @@ -98,7 +102,7 @@ static int mhi_find_next_file_offset(struct mhi_controller *mhi_cntrl, return 0; } -void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) +void mhi_dump_sfr(struct mhi_controller *mhi_cntrl, char *buf, size_t len) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; struct rddm_header *rddm_header = @@ -107,6 +111,11 @@ void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) struct file_info info = {0}; u32 table_size, n; + if (buf == NULL || len == 0) { + MHI_ERR("invalid sfr buf\n"); + return; + } + if (rddm_header->header_size > sizeof(*rddm_header) || rddm_header->header_size < 8) { MHI_CNTRL_ERR("invalid reported header size %u\n", @@ -127,7 +136,7 @@ void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) if (!strcmp(table_info->file_name, "Q6-SFR.bin")) { info.file_size = table_info->size; - mhi_process_sfr(mhi_cntrl, &info); + mhi_process_sfr(mhi_cntrl, &info, buf, len); return; } @@ -574,7 +583,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) "No firmware image defined or !sbl_size || !seg_len\n"); return; } - + MHI_LOG("loading firmware fw_name=%s\n", fw_name); ret = request_firmware(&firmware, fw_name, mhi_cntrl->dev); if (ret) { if (!mhi_cntrl->fw_image_fallback) { diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 63deaca35045..3f333c3c07ee 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1672,6 +1672,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) mhi_cntrl->parent = debugfs_lookup(mhi_bus_type.name, NULL); mhi_cntrl->klog_lvl = MHI_MSG_LVL_ERROR; + mhi_cntrl->log_lvl = MHI_MSG_LVL_VERBOSE; /* adding it to this list only for debug purpose */ mutex_lock(&mhi_bus.lock); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 3053aca7cd80..933a8b508e8f 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -805,6 +805,7 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) struct mhi_device *mhi_dev; int ret; + MHI_ERR(":%s\n", __func__); mhi_chan = mhi_cntrl->mhi_chan; for (i = 0; i < mhi_cntrl->max_chan; i++, mhi_chan++) { if (!mhi_chan->configured || mhi_chan->mhi_dev || diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 8362b19ba056..f472a964d4fc 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -812,7 +812,8 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, spin_lock_irqsave(&mhi_cntrl->transition_lock, flags); list_add_tail(&item->node, &mhi_cntrl->transition_list); spin_unlock_irqrestore(&mhi_cntrl->transition_lock, flags); - + MHI_LOG("%s state to :%s\n", __func__, + TO_MHI_STATE_TRANS_STR(item->state)); queue_work(mhi_cntrl->wq, &mhi_cntrl->st_worker); return 0; diff --git a/drivers/bus/mhi/devices/mhi_satellite.c b/drivers/bus/mhi/devices/mhi_satellite.c index 24621475a268..b32e1b2ad041 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/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c index 2a7fbfa7062a..6c70d63eb472 100644 --- a/drivers/bus/mhi/devices/mhi_uci.c +++ b/drivers/bus/mhi/devices/mhi_uci.c @@ -537,7 +537,7 @@ static void mhi_uci_remove(struct mhi_device *mhi_dev) { struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev); - MSG_LOG("Enter\n"); + MSG_ERR("Enter\n"); mutex_lock(&mhi_uci_drv.lock); @@ -632,7 +632,7 @@ static int mhi_uci_probe(struct mhi_device *mhi_dev, mutex_unlock(&mhi_uci_drv.lock); mutex_unlock(&uci_dev->mutex); - MSG_LOG("channel:%s successfully probed\n", mhi_dev->chan_name); + MSG_ERR("channel:%s %s %s successfully probed\n", mhi_dev->chan_name, __func__, node_name); return 0; }; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 083c303115dd..2ee9893a1c2d 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -182,6 +182,12 @@ static int fastrpc_pdr_notifier_cb(struct notifier_block *nb, static struct dentry *debugfs_root; static struct dentry *debugfs_global_file; +static atomic_t total_buf_size; +int read_fastrpc_usage(void) +{ + return atomic_read(&total_buf_size) / PAGE_SIZE; +} + static inline void mem_barrier(void) { __asm__ __volatile__("dmb sy":::"memory"); @@ -677,6 +683,7 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) srcVM, 2, destVM, destVMperm, 1); } trace_fastrpc_dma_free(fl->cid, buf->phys, buf->size); + atomic_sub(buf->size, &total_buf_size); dma_free_attrs(fl->sctx->smmu.dev, buf->size, buf->virt, buf->phys, buf->dma_attr); } @@ -1187,6 +1194,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size, buf->flags = rflags; buf->raddr = 0; buf->remote = 0; + atomic_add(size, &total_buf_size); buf->virt = dma_alloc_attrs(fl->sctx->smmu.dev, buf->size, (dma_addr_t *)&buf->phys, GFP_KERNEL, buf->dma_attr); diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 7635f6d87faf..e728d707b0c5 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -22,6 +22,7 @@ #include "diagfwd_mhi.h" #include "diag_dci.h" #include "diag_ipc_logging.h" +#include "diagfwd.h" #ifdef CONFIG_MHI_BUS #define diag_mdm_init diag_mhi_init @@ -308,8 +309,35 @@ int diagfwd_bridge_close(int id) return 0; } +bool diagfwd_bridge_is_quit_cmd(unsigned char *buf) +{ + uint16_t cmd_code; + uint16_t subsys_id; + uint16_t cmd_code_lo; + uint16_t cmd_code_hi; + unsigned char *temp = NULL; + + temp = buf; + cmd_code = (uint16_t)(*(uint8_t *)temp); + temp += sizeof(uint8_t); + subsys_id = (uint16_t)(*(uint8_t *)temp); + temp += sizeof(uint8_t); + cmd_code_hi = (uint16_t)(*(uint16_t *)temp); + cmd_code_lo = (uint16_t)(*(uint16_t *)temp); + if (cmd_code == 0x4b && subsys_id == 0xb && + cmd_code_hi == 0x35 && cmd_code_lo == 0x35) { + pr_err("diag command with 75 11 53\n"); + return true; + } + return false; +} int diagfwd_bridge_write(int id, unsigned char *buf, int len) { + if (diagfwd_bridge_is_quit_cmd(buf) && !driver->hdlc_disabled) + diag_process_hdlc_pkt(buf, len, 0); + else if (diagfwd_bridge_is_quit_cmd(buf + 4*sizeof(uint8_t))) + diag_process_non_hdlc_pkt(buf, len, 0); + if (id < 0 || id >= NUM_REMOTE_DEV) return -EINVAL; if (bridge_info[id].dev_ops && bridge_info[id].dev_ops->write) { diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 53cfe574d8d4..a94f290cec08 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 5b463b486ec0..9ec0fa101d92 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,10 @@ struct clk_core { struct hlist_node child_node; struct hlist_head clks; unsigned int notifier_count; -#ifdef CONFIG_DEBUG_FS +//#ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct hlist_node debug_node; -#endif +//#endif struct kref ref; struct clk_vdd_class *vdd_class; int vdd_class_vote; @@ -3213,10 +3219,11 @@ EXPORT_SYMBOL_GPL(clk_set_flags); /*** debugfs support ***/ -#ifdef CONFIG_DEBUG_FS +//#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 +3947,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,56 +4002,68 @@ 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); - 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, @@ -4028,6 +4082,112 @@ void clock_debug_print_enabled(void) { } #endif +*/ + +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; +} + +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; +} + +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; +} + +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; +} /** * __clk_core_init - initialize the data structures in a struct clk_core @@ -4284,6 +4444,9 @@ out: 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/clk-debug.c b/drivers/clk/qcom/clk-debug.c index e7af0538dc04..f2413c59f141 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -282,6 +282,50 @@ exit: 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-kona.c b/drivers/clk/qcom/debugcc-kona.c index b12a34d0a9da..b49a20fc819f 100644 --- a/drivers/clk/qcom/debugcc-kona.c +++ b/drivers/clk/qcom/debugcc-kona.c @@ -974,6 +974,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_memnoc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b050316480fc..833266cf37e7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -33,7 +33,16 @@ #include #include +#include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif +#ifdef CONFIG_PCCORE +#include +#endif +#define GOLD_CPU_NUMBER 4 +#define GOLD_PLUS_CPU_NUMBER 7 static LIST_HEAD(cpufreq_policy_list); @@ -60,6 +69,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 @@ -358,7 +390,8 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, 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,14 +540,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; + +#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); + 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); +#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 policy->cached_target_freq = target_freq; if (cpufreq_driver->target_index) { int idx; - +#ifdef 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); + trace_cpu_frequency_select(target_freq, policy->freq_table[idx].frequency, idx, policy->cpu, 1); +#else + idx = cpufreq_frequency_table_target(policy, target_freq, CPUFREQ_RELATION_L); +#endif policy->cached_resolved_idx = idx; return policy->freq_table[idx].frequency; } @@ -905,6 +965,17 @@ 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 +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 + 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 +986,9 @@ 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 +cpufreq_freq_attr_ro(freq_change_info); +#endif cpufreq_freq_attr_rw(scaling_min_freq); cpufreq_freq_attr_rw(scaling_max_freq); cpufreq_freq_attr_rw(scaling_governor); @@ -932,6 +1006,9 @@ static struct attribute *default_attrs[] = { &scaling_driver.attr, &scaling_available_governors.attr, &scaling_setspeed.attr, +#ifdef CONFIG_ONEPLUS_HEALTHINFO + &freq_change_info.attr, +#endif NULL }; @@ -1152,6 +1229,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 +1362,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 +1992,9 @@ 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); +#ifdef CONFIG_PCCORE + trace_cpu_frequency_select(target_freq, ret, -2, policy->cpu, 2); +#endif if (ret) { cpufreq_times_record_transition(policy, ret); cpufreq_stats_record_transition(policy, ret); @@ -2008,6 +2097,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 +2341,10 @@ 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 + policy->org_max = new_policy->max; +#endif + memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); /* @@ -2284,8 +2381,17 @@ 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 + strlcpy(policy->change_comm, current->comm, TASK_COMM_LEN); +#endif arch_set_max_freq_scale(policy->cpus, policy->max); policy->cached_target_freq = UINT_MAX; @@ -2648,3 +2754,276 @@ 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); + + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + 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); + + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + 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; + } + 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); + + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + 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; + } + 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) +{ + 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 dafb679adc58..d1346cf52241 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 21b919bfaecc..4d4782a4ac4c 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 e1f1331fb763..e45f871b1ce3 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -16,6 +16,12 @@ #include #include +#ifdef CONFIG_PCCORE +#include +#include +#include +#include +#endif #define CREATE_TRACE_POINTS #include @@ -325,11 +331,51 @@ qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { int index; - +#ifdef 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; +#endif index = policy->cached_resolved_idx; if (index < 0) return 0; +#ifdef 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; + } + } + + if (policy->freq_table[index].frequency < policy->min) + index = policy->min_idx; + } +done: + trace_find_freq(idx_cache, target_freq, index, policy->freq_table[index].frequency, + policy->cpu, op_enable, dp_level_mode, dp_level); +#endif 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 30ba39d66772..e30a0411ffe6 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -43,6 +43,9 @@ #include "../clk/clk.h" #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif #define SCLK_HZ (32768) #define PSCI_POWER_STATE(reset) (reset << 30) @@ -125,6 +128,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 +661,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 +678,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 234c14b8ec8d..d4ce6f203cb3 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,20 @@ int update_devfreq(struct devfreq *devfreq) flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ } +#ifdef CONFIG_CONTROL_CENTER + if (cc_ddr_boost_enabled()) { + if (devfreq->dev.cc_marked) { + unsigned long val; + + 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 +534,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 +684,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 af8440bc0ba8..333f7d8d6504 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,43 @@ 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); + + 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 +242,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 +279,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 +334,19 @@ 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) +{ + 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/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 2a0dcc95f2f0..79ebc75b0f83 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -9,6 +9,10 @@ #include #include #include "esoc-mdm.h" +#include +#include +#include +#include enum gpio_update_config { GPIO_UPDATE_BOOTING_CONFIG = 1, @@ -363,6 +367,41 @@ static void mdm_status_fn(struct work_struct *work) mdm_update_gpio_configs(mdm, GPIO_UPDATE_RUNNING_CONFIG); } +int esoc_ssr_state; +int mdm_umount_state; +module_param(mdm_umount_state, int, 0644); +MODULE_PARM_DESC(mdm_umount_state, "mdm_umount_state "); + +int ap_mdm_dump_once(void) +{ + return 1; +} +int set_esoc_ssr_state(int state) +{ + esoc_ssr_state = state; + return 0; +} +int get_esoc_ssr_state(void) +{ + return esoc_ssr_state; +} + +int get_mdm_umount_state(void) +{ + int i = 0; + + for (i = 0; i < 10; i++) { + if (!mdm_umount_state) { + esoc_mdm_log("mdm_umount_state=%d i=%d\n", mdm_umount_state, i); + pr_err("mdm_umount_state=%d i=%d\n", mdm_umount_state, i); + msleep(1000); + } else + break; + } + msleep(3000); + return 0; +} + static void mdm_get_restart_reason(struct work_struct *work) { int ret, ntries = 0; @@ -377,6 +416,9 @@ static void mdm_get_restart_reason(struct work_struct *work) if (!ret) { esoc_mdm_log("restart reason is %s\n", sfr_buf); dev_err(dev, "mdm restart reason is %s\n", sfr_buf); + dev_err(dev, "[OEM_MDM] SSR: send esoc crash reason\n"); + subsys_store_crash_reason(mdm->esoc->subsys_dev, sfr_buf); + subsys_send_uevent_notify(&mdm->esoc->subsys); break; } msleep(SFR_RETRY_INTERVAL); @@ -387,6 +429,27 @@ static void mdm_get_restart_reason(struct work_struct *work) __func__, ret); } mdm->get_restart_reason = false; + + if (get_esoc_ssr_state() || oem_get_twice_modemdump_state()) { + if (oem_get_download_mode()) { + char fusion_buf[] = "\r\nSDX5x esoc0 modem crash"; + char twice_buf[] = "\r\nTwice Dump To Get Modem Dump\r\n"; + + if (oem_get_modemdump_mode()) + strlcat(sfr_buf, twice_buf, RD_BUF_SIZE); + else + strlcat(sfr_buf, fusion_buf, RD_BUF_SIZE); + esoc_mdm_log("Trigger panic by OEM to get SDX5x dump!\n"); + dev_err(dev, "Trigger panic by OEM to get SDX5x dump!\n"); + msleep(5000); + send_msg_sync_mdm_dump(); + get_mdm_umount_state(); + qpnp_pon_modem_pwr_off(PON_POWER_OFF_SHUTDOWN); + msleep(500); + panic(sfr_buf); + } + set_esoc_ssr_state(0); + } } void mdm_wait_for_status_low(struct mdm_ctrl *mdm, bool atomic) @@ -559,7 +622,7 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) esoc_clink_evt_notify(ESOC_BOOT_STATE, esoc); mdm_trigger_dbg(mdm); queue_work(mdm->mdm_queue, &mdm->mdm_status_work); - if (mdm->get_restart_reason) + if (mdm->get_restart_reason || oem_get_twice_modemdump_state()) queue_work(mdm->mdm_queue, &mdm->restart_reason_work); if (esoc->auto_boot) esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc); diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 5301be93d38f..e7cf3da0617a 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -11,6 +11,8 @@ #include "esoc.h" #include "esoc-mdm.h" #include "mdm-dbg.h" +#include +#include /* Default number of powerup trial requests per session */ #define ESOC_DEF_PON_REQ 3 @@ -57,6 +59,13 @@ struct mdm_drv { #define S3_RESET_DELAY_MS 1000 +bool oem_twice_modemdump_en; +bool oem_get_twice_modemdump_state(void) +{ + return oem_twice_modemdump_en; +} +EXPORT_SYMBOL(oem_get_twice_modemdump_state); + static void esoc_client_link_power_off(struct esoc_clink *esoc_clink, unsigned int flags); static void esoc_client_link_mdm_crash(struct esoc_clink *esoc_clink); @@ -448,6 +457,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; int timeout = INT_MAX; u8 pon_trial = 0; + oem_twice_modemdump_en = false; esoc_mdm_log("Powerup request from SSR\n"); @@ -517,6 +527,11 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) esoc_mdm_log( "Boot failed. Doing cleanup and attempting to retry\n"); mdm_subsys_retry_powerup_cleanup(esoc_clink, 0); + if (oem_get_download_mode() && oem_get_modemdump_mode()) { + pr_err("[MDM] Trigger OEM TWICE modemdump\n"); + esoc_mdm_log("[MDM] Trigger OEM TWICE modemdump\n"); + oem_twice_modemdump_en = true; + } } else if (mdm_drv->pon_state == PON_SUCCESS) { break; } diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c index 7d72ab11f403..1ad3a8ffb413 100644 --- a/drivers/esoc/esoc-mdm-pon.c +++ b/drivers/esoc/esoc-mdm-pon.c @@ -252,7 +252,7 @@ static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm) mdm->soft_reset_inverted = 1; return 0; } else - return -EIO; + return 0; } static int mdm4x_pon_setup(struct mdm_ctrl *mdm) diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 7ab2b74ed528..e0f187720844 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 9dcd24b25d65..632a7794da1f 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,13 +16,14 @@ #include #include #include +#include #include #include #include /* QSEE_LOG_BUF_SIZE = 32K */ -#define QSEE_LOG_BUF_SIZE 0x8000 +#define QSEE_LOG_BUF_SIZE 0x10000 /* TZ Diagnostic Area legacy version number */ @@ -781,7 +781,7 @@ 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)); if (*tz_id == TZDBG_BOOT || *tz_id == TZDBG_RESET || *tz_id == TZDBG_INTERRUPT || *tz_id == TZDBG_GENERAL || @@ -899,10 +899,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 +910,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 +926,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 +942,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,8 +1089,10 @@ 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); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8750f3f02b3f..0b0fe03bf852 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -115,8 +115,90 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 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); +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); +extern int iris_loop_back_test(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_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); +u64 dsi_display_get_serial_number_at(struct drm_connector *connector); +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_mca_setting_mode(struct drm_connector *connector, int mca_setting_mode); +int dsi_display_get_mca_setting_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 3eb8b2a52d58..a004b5e2fbba 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -1096,6 +1096,43 @@ int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, } EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); +/** + * mipi_dsi_dcs_set_display_brightness_samsung() - sets the brightness value of the + * display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +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 ecb7b33002bb..0628e15573d4 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -21,10 +21,29 @@ #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_S6E3HC2 0 +#define DSI_PANEL_SAMSUNG_S6E3FC2X01 1 +#define DSI_PANEL_SAMSUNG_SOFEF03F_M 2 +#define DSI_PANEL_SAMSUNG_ANA6705 3 +#define DSI_PANEL_SAMSUNG_ANA6706 4 +#define DSI_PANEL_SAMSUNG_AMB655XL 5 + +int dsi_cmd_log_enable; +EXPORT_SYMBOL(dsi_cmd_log_enable); + /** * DOC: overview * @@ -228,17 +247,1328 @@ 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) { + 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("19821 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_ANA6706) || + (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_ANA6706) || + (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, "%d\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; + } + pr_err("node aod_mode=%d\n", aod_mode); + 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 mca_setting_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int mca_setting_mode = 0; + + mca_setting_mode = dsi_display_get_mca_setting_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", mca_setting_mode); + return ret; +} + +static ssize_t mca_setting_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 mca_setting_mode = 0; + + ret = kstrtoint(buf, 10, &mca_setting_mode); + if (ret) { + pr_err("Kstrtoint failed, ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_mca_setting_mode(connector, mca_setting_mode); + if (ret) + pr_err("Set mca setting mode %d failed\n", mca_setting_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_S6E3HC2) { + 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 if (dsi_panel_name == DSI_PANEL_SAMSUNG_SOFEF03F_M) { + dsi_display_get_serial_number(connector); + panel_stage_info = dsi_display_get_stage_info(connector); + + if (panel_stage_info == 0x27) + pvt_mp_panel_flag = 1; + else + pvt_mp_panel_flag = 0; + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", 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 ret = 0; + + 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 panel_tool = 0; + int ddic_y = 0; + int ddic_x = 0; + + char *stage_string_info = NULL; + char *production_string_info = NULL; + char *ddic_check_result = NULL; + char *panel_tool_result = NULL; + char *buf_select = NULL; + + 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); + + if (dsi_panel_name == DSI_PANEL_SAMSUNG_S6E3HC2) { + if (panel_code_info == 0xED) { + if (panel_stage_info == 0x02) + stage_string_info = "STAGE: EVT2"; + else if (panel_stage_info == 0x03) + stage_string_info = "STAGE: EVT2(NEW_DIMMING_SET)"; + else if (panel_stage_info == 0x99) + stage_string_info = "STAGE: EVT2(113MHZ_OSC)"; + 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: DVT3"; + else if (panel_stage_info == 0x07) + stage_string_info = "STAGE: PVT/MP(112MHZ_OSC)"; + else if (panel_stage_info == 0x10) + stage_string_info = "STAGE: PVT/MP(113MHZ_OSC)"; + else if (panel_stage_info == 0x11) + stage_string_info = "STAGE: PVT(113MHZ_OSC+X_TALK_IMPROVEMENT)"; + else + stage_string_info = "STAGE: UNKNOWN"; + + if (panel_production_info == 0x0C) + production_string_info = "TPIC: LSI\nCOVER: JNTC\nOTP_GAMMA: 90HZ"; + else if (panel_production_info == 0x0E) + production_string_info = "TPIC: LSI\nCOVER: LENS\nOTP_GAMMA: 90HZ"; + else if (panel_production_info == 0x1C) + production_string_info = "TPIC: STM\nCOVER: JNTC\nOTP_GAMMA: 90HZ"; + else if (panel_production_info == 0x6C) + production_string_info = "TPIC: LSI\nCOVER: JNTC\nOTP_GAMMA: 60HZ"; + else if (panel_production_info == 0x6E) + production_string_info = "TPIC: LSI\nCOVER: LENS\nOTP_GAMMA: 60HZ"; + else if (panel_production_info == 0x1E) + production_string_info = "TPIC: STM\nCOVER: LENS\nOTP_GAMMA: 90HZ"; + else if (panel_production_info == 0x0D) + production_string_info = "TPIC: LSI\nID3: 0x0D\nOTP_GAMMA: 90HZ"; + else + production_string_info = "TPIC: UNKNOWN\nCOVER: UNKNOWN\nOTP_GAMMA: UNKNOWN"; + + ret = scnprintf(buf, PAGE_SIZE, "%04d/%02d/%02d %02d:%02d:%02d\n%s\n%s\nID: %02X %02X %02X\n", + panel_year, panel_mon, panel_day, panel_hour, panel_min, panel_sec, + stage_string_info, production_string_info, panel_code_info, + panel_stage_info, panel_production_info); + } + + if (panel_code_info == 0xEE) { + if (panel_stage_info == 0x12) + stage_string_info = "STAGE: T0/EVT1"; + else if (panel_stage_info == 0x13) + stage_string_info = "STAGE: EVT2"; + else if (panel_stage_info == 0x14) + stage_string_info = "STAGE: EVT2"; + else if (panel_stage_info == 0x15) + stage_string_info = "STAGE: EVT3"; + else if (panel_stage_info == 0x16) + stage_string_info = "STAGE: DVT"; + else if (panel_stage_info == 0x17) + stage_string_info = "STAGE: DVT"; + else if (panel_stage_info == 0x19) + stage_string_info = "STAGE: PVT/MP"; + else + stage_string_info = "STAGE: UNKNOWN"; + + ret = scnprintf(buf, PAGE_SIZE, "%04d/%02d/%02d %02d:%02d:%02d\n%s\nID: %02X %02X %02X\n", + panel_year, panel_mon, panel_day, panel_hour, panel_min, panel_sec, + stage_string_info, panel_code_info, panel_stage_info, + panel_production_info); + } + + } else if (dsi_panel_name == DSI_PANEL_SAMSUNG_SOFEF03F_M) { + if (panel_stage_info == 0x01) + stage_string_info = "STAGE: T0"; + else if (panel_stage_info == 0x21) + stage_string_info = "STAGE: EVT1"; + else if (panel_stage_info == 0x22) + stage_string_info = "STAGE: EVT2"; + else if (panel_stage_info == 0x24) + stage_string_info = "STAGE: DVT1-1"; + else if (panel_stage_info == 0x26) + stage_string_info = "STAGE: DVT1-2"; + else if (panel_stage_info == 0x25) + stage_string_info = "STAGE: DVT2"; + else if (panel_stage_info == 0x28) + stage_string_info = "STAGE: DVT3"; + else if (panel_stage_info == 0x27) + stage_string_info = "STAGE: PVT/MP"; + + ret = scnprintf(buf, PAGE_SIZE, "%04d/%02d/%02d %02d:%02d:%02d\n%s\nID: %02X %02X %02X\n", + panel_year, panel_mon, panel_day, panel_hour, panel_min, panel_sec, stage_string_info, + panel_code_info, panel_stage_info, panel_production_info); + } else if (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"; + else + stage_string_info = "STAGE: UNKNOWN"; + + ddic_check_info = dsi_display_get_ddic_check_info(connector); + if (ddic_check_info == 1) + ddic_check_result = "OK"; + else if (ddic_check_info == 0) + ddic_check_result = "NG"; + + ret = scnprintf(buf, PAGE_SIZE, + "%04d/%02d/%02d\n%02d:%02d:%02d:%03d.%01d\n%s\nID: %02X %02X %02X\nDDIC_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 if (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6706) { + panel_ic_v_info = dsi_display_get_panel_ic_v_info(connector); + + if (panel_stage_info == 0x01) + stage_string_info = "STAGE: T0"; + else if (panel_stage_info == 0x02) + stage_string_info = "STAGE: EVT1-1"; + else if ((panel_stage_info == 0xA2) && (panel_ic_v_info == 1)) + stage_string_info = "STAGE: EVT2"; + else if ((panel_stage_info == 0xA3) && (panel_ic_v_info == 1)) + stage_string_info = "STAGE: EVT2-1"; + else if ((panel_stage_info == 0xA3) && (panel_ic_v_info == 0)) + stage_string_info = "STAGE: EVT2-2"; + else if (panel_stage_info == 0xA4) + stage_string_info = "STAGE: DVT1"; + else if (panel_stage_info == 0xA5) + stage_string_info = "STAGE: DVT2"; + else if (panel_stage_info == 0xA6) + stage_string_info = "STAGE: PVT/MP"; + else + stage_string_info = "STAGE: UNKNOWN"; + + ddic_check_info = dsi_display_get_ddic_check_info(connector); + if (ddic_check_info == 1) + ddic_check_result = "OK"; + else if (ddic_check_info == 0) + ddic_check_result = "NG"; + + panel_tool = dsi_display_get_ToolsType_ANA6706(connector); + if (panel_tool == 0) + panel_tool_result = "ToolB"; + else if (panel_tool == 1) + panel_tool_result = "ToolA"; + else if (panel_tool == 2) + panel_tool_result = "ToolA_HVS30"; + else + panel_tool_result = "Indistinguishable"; + + ddic_y = dsi_display_get_ddic_coords_Y(connector); + ddic_x = dsi_display_get_ddic_coords_X(connector); + + buf_select = dsi_display_get_ic_reg_buf(connector); + if (buf_select == NULL) + return ret; + + ret = scnprintf(buf, PAGE_SIZE, + "%04d/%02d/%02d\n%02d:%02d:%02d:%03d.%01d\n%s\nID: %02X %02X %02X\n" + "IC_V: %02d\nDDIC_Check_Result: %s\nTool: %s\nddic_y: %02d ddic_x: %02d\nLotid: %s\n" + "reg: %02x %02x %02x %02x %02x %02x %02x\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, panel_ic_v_info, ddic_check_result, panel_tool_result, + ddic_y, ddic_x, buf_Lotid, buf_select[0], buf_select[1], buf_select[2], + buf_select[3], buf_select[4], buf_select[5], buf_select[6]); + } else if (dsi_panel_name == DSI_PANEL_SAMSUNG_AMB655XL) { + 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: DVT1"; + else if (panel_stage_info == 0x04) + stage_string_info = "STAGE: DVT2"; + else if (panel_stage_info == 0x05) + stage_string_info = "STAGE: PVT/MP"; + else + stage_string_info = "STAGE: UNKNOWN"; + + ret = scnprintf(buf, PAGE_SIZE, "%04d/%02d/%02d\n%02d:%02d:%02d:%03d.%01d\n%s\nID: %02X %02X %02X\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); + } else { + ret = scnprintf(buf, PAGE_SIZE, "%04d/%02d/%02d %02d:%02d:%02d\nID: %02X %02X %02X\n", + panel_year, panel_mon, panel_day, panel_hour, panel_min, panel_sec, + panel_code_info, panel_stage_info, panel_production_info); + } + + return ret; +} + +static ssize_t panel_serial_number_AT_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "%llu\n", dsi_display_get_serial_number_at(connector)); + + return ret; +} + +static ssize_t iris_recovery_mode_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + int result = 0; + struct drm_connector *connector = to_drm_connector(dev); + + result = iris_loop_back_test(connector); + pr_err("iris_loop_back_test result = %d", result); + ret = scnprintf(buf, PAGE_SIZE, "%d\n", (result == 0) ? 1 : 0); + + 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) +{ + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "dither switch = %d\n" + "0 -- dither switch off\n" + "other -- dither switch on\n", + op_dither_enable); + + return ret; +} + +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 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_RW(mca_setting); +static DEVICE_ATTR_RO(gamma_test); +static DEVICE_ATTR_RO(panel_serial_number); +static DEVICE_ATTR_RO(panel_serial_number_AT); +static DEVICE_ATTR_RO(iris_recovery_mode_check); +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_mca_setting.attr, + &dev_attr_gamma_test.attr, + &dev_attr_panel_serial_number.attr, + &dev_attr_panel_serial_number_AT.attr, + &dev_attr_iris_recovery_mode_check.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 40daa34a3278..cb3b8ae160b4 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) @@ -4731,6 +4732,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; @@ -4748,6 +4750,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); @@ -4789,6 +4794,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); @@ -4796,6 +4819,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, @@ -4830,12 +4878,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_pool.c b/drivers/gpu/msm/kgsl_pool.c index a6906b85c6d3..9687e4e1cf39 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -107,7 +107,7 @@ kgsl_pool_size(struct kgsl_page_pool *kgsl_pool) } /* Returns the number of pages in all kgsl page pools */ -static int kgsl_pool_size_total(void) +int kgsl_pool_size_total(void) { int i; int total = 0; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 4eaeadedc479..bcdd6a225861 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -16,6 +16,9 @@ #include "kgsl_pwrscale.h" #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 @@ -2437,6 +2440,9 @@ 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/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index d5f06dffb7de..b938a2249f9a 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -931,6 +931,10 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_AMUX_THM4_PU1] = ADC_CHAN_VOLT("gpio1_v", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_GPIO4_PU1] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) }; static const struct adc_channels adc7_chans_pmic[ADC_MAX_CHANNEL] = { diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 492a971b95b5..eb21bfeba011 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; @@ -43,6 +44,7 @@ struct gpio_button_data { unsigned int release_delay; /* in msecs, for IRQ-only buttons */ struct delayed_work work; + struct delayed_work press_vol_up; unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */ unsigned int irq; @@ -373,6 +375,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); @@ -393,9 +397,34 @@ static void gpio_keys_gpio_work_func(struct work_struct *work) pm_relax(bdata->input->dev.parent); } +static void gpio_vol_up_work_func(struct work_struct *work) +{ + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, press_vol_up.work); + const struct gpio_keys_button *button = bdata->button; + struct input_dev *input = bdata->input; + int state; + + state = gpiod_get_value_cansleep(bdata->gpiod); + if (state < 0) { + dev_err(input->dev.parent, + "failed to get gpio state: %d\n", state); + return; + } + + if (state && button->code == KEY_VOLUMEUP) { + set_vol_up_status(KEY_PRESSED); + compound_key_to_get_trace("system_server"); + compound_key_to_get_tombstone("surfaceflinger"); + } +} + static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; + const struct gpio_keys_button *button = bdata->button; + struct input_dev *input = bdata->input; + int state; BUG_ON(irq != bdata->irq); @@ -418,6 +447,21 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) &bdata->work, msecs_to_jiffies(bdata->software_debounce)); + if (button->code == KEY_VOLUMEUP) { + state = gpiod_get_value(bdata->gpiod); + if (state < 0) { + dev_err(input->dev.parent, + "failed to get gpio state: %d\n", state); + return IRQ_NONE; + } + + if (state) + schedule_delayed_work(&bdata->press_vol_up, msecs_to_jiffies(6000)); + else { + set_vol_up_status(KEY_RELEASED); + cancel_delayed_work(&bdata->press_vol_up); + } + } return IRQ_HANDLED; } @@ -568,6 +612,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, } INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); + INIT_DELAYED_WORK(&bdata->press_vol_up, gpio_vol_up_work_func); isr = gpio_keys_gpio_isr; irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 442e398aed3c..b4fc5192f2d9 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -173,6 +173,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 0fd3003490a5..9c56ee2b4dbf 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,64 +221,104 @@ 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 int @@ -941,6 +959,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"); + set_pwr_status(KEY_RELEASED); + schedule_work(&pon->up_work); + cancel_delayed_work(&pon->press_work); + cancel_delayed_work(&pon->press_pwr); +#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"); + schedule_delayed_work(&pon->press_work, msecs_to_jiffies(4000)); + schedule_delayed_work(&pon->press_pwr, msecs_to_jiffies(6000)); +#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 +1014,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 +1164,160 @@ 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 display_bl, boot_mode; + 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"); + display_bl = dsi_panel_backlight_get(); + boot_mode = get_boot_mode(); + if (display_bl == 0 && boot_mode == MSM_BOOT_MODE_NORMAL) { + oem_force_minidump_mode(); + get_init_sched_info(); + show_state_filter(TASK_UNINTERRUPTIBLE); + send_sig_to_get_trace("system_server"); + send_sig_to_get_tombstone("surfaceflinger"); + ksys_sync(); + panic("power key still pressed\n"); + } + } + msleep(20); + ksys_sync(); +err_return: + return; +} + +static void press_pwr_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_pwr.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 6s Power-Key is still DOWN\n"); + set_pwr_status(KEY_PRESSED); + compound_key_to_get_trace("system_server"); + compound_key_to_get_tombstone("surfaceflinger"); + } + 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 +1348,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 +2340,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 +2660,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 +2691,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 +2703,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; } @@ -2290,7 +2826,8 @@ static int qpnp_pon_probe(struct platform_device *pdev) dev_err(dev, "qcom,modem-reset and qcom,system-reset properties cannot be supported together for one PMIC PON device\n"); return -EINVAL; } - + if (to_spmi_device(dev->parent)->usid == 10) + op_pm8998_regmap_register(pon->regmap); /* Get the total number of pon configurations and regulators */ for_each_available_child_of_node(dev->of_node, node) { if (of_find_property(node, "regulator-name", NULL)) { @@ -2321,6 +2858,12 @@ 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); + INIT_DELAYED_WORK(&pon->press_pwr, press_pwr_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/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d3c215d7b4eb..c4924623de4e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1340,7 +1340,7 @@ source "drivers/input/touchscreen/synaptics_dsx/Kconfig" config TOUCHSCREEN_SYNAPTICS_TCM bool "Synaptics TCM Touchscreen Driver" depends on I2C - default y + default n help Say Y here if you have a Synaptics Touchscreen. diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 3d0ae38d550a..3d57b7d431dd 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -41,7 +41,8 @@ #include #include - +/* Add for battery historian */ +#include #include "irq-gic-common.h" struct redist_region { @@ -371,6 +372,10 @@ 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); } } diff --git a/drivers/irqchip/msm_show_resume_irq.c b/drivers/irqchip/msm_show_resume_irq.c index 1bf7040249ff..40497a872211 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/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c index bb520c1910de..b96e9e8655e5 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.c +++ b/drivers/media/platform/msm/cvp/cvp_hfi.c @@ -350,32 +350,6 @@ int get_pkt_index(struct cvp_hal_session_cmd_pkt *hdr) return -EINVAL; } -int set_feature_bitmask(int pkt_idx, unsigned long *bitmask) -{ - if (!bitmask) { - dprintk(CVP_ERR, "%s: invalid bitmask\n", __func__); - return -EINVAL; - } - - if (cvp_hfi_defs[pkt_idx].type == HFI_CMD_SESSION_CVP_DME_FRAME) { - set_bit(DME_BIT_OFFSET, bitmask); - return 0; - } - - if (cvp_hfi_defs[pkt_idx].type == HFI_CMD_SESSION_CVP_ICA_FRAME) { - set_bit(ICA_BIT_OFFSET, bitmask); - return 0; - } - - if (cvp_hfi_defs[pkt_idx].type == HFI_CMD_SESSION_CVP_FD_FRAME) { - set_bit(FD_BIT_OFFSET, bitmask); - return 0; - } - - dprintk(CVP_ERR, "%s: invalid pkt_idx %d\n", __func__, pkt_idx); - return -EINVAL; -} - int get_hfi_version(void) { struct msm_cvp_core *core; diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_api.h b/drivers/media/platform/msm/cvp/cvp_hfi_api.h index 736038efe40e..85186eca80d5 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_api.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_api.h @@ -98,12 +98,6 @@ #define HFI_MODEL_BUFFERS_OFFSET 7 #define HFI_MODEL_BUF_NUM 1 -#define DFS_BIT_OFFSET (CVP_KMD_HFI_DFS_FRAME_CMD - CVP_KMD_CMD_START) -#define DME_BIT_OFFSET (CVP_KMD_HFI_DME_FRAME_CMD - CVP_KMD_CMD_START) -#define PERSIST_BIT_OFFSET (CVP_KMD_HFI_PERSIST_CMD - CVP_KMD_CMD_START) -#define ICA_BIT_OFFSET (CVP_KMD_HFI_ICA_FRAME_CMD - CVP_KMD_CMD_START) -#define FD_BIT_OFFSET (CVP_KMD_HFI_FD_FRAME_CMD - CVP_KMD_CMD_START) - #define HFI_VERSION_MAJOR_MASK 0xFF000000 #define HFI_VERSION_MAJOR_SHFIT 24 #define HFI_VERSION_MINOR_MASK 0x00FFFFE0 @@ -428,7 +422,6 @@ void cvp_hfi_deinitialize(enum msm_cvp_hfi_type hfi_type, int get_pkt_index(struct cvp_hal_session_cmd_pkt *hdr); int get_signal_from_pkt_type(unsigned int type); -int set_feature_bitmask(int pkt_index, unsigned long *bitmask); int get_hfi_version(void); unsigned int get_msg_size(void); unsigned int get_msg_session_id(void *msg); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h index f8fe274ed70d..a202a12017e8 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h @@ -287,11 +287,10 @@ struct cvp_hfi_client { u32 transaction_id; u32 data1; u32 data2; - u32 kdata1; - u32 kdata2; + u64 kdata; u32 reserved1; u32 reserved2; -}; +} __packed; struct cvp_hfi_client_d { u32 transaction_id; @@ -319,7 +318,7 @@ struct cvp_hfi_cmd_session_set_buffers_packet { u32 session_id; struct cvp_hfi_client client_data; struct cvp_hfi_buf_type buf_type; -}; +} __packed; struct cvp_hfi_cmd_session_set_buffers_packet_d { u32 size; @@ -339,7 +338,7 @@ struct cvp_session_release_buffers_packet { u32 buffer_type; u32 num_buffers; u32 buffer_idx; -}; +} __packed; struct cvp_session_release_buffers_packet_d { u32 size; @@ -357,7 +356,7 @@ struct cvp_hfi_cmd_session_hdr { u32 session_id; struct cvp_hfi_client client_data; u32 stream_idx; -}; +} __packed; struct cvp_hfi_msg_session_hdr { u32 size; @@ -366,7 +365,7 @@ struct cvp_hfi_msg_session_hdr { u32 error_type; struct cvp_hfi_client client_data; u32 stream_idx; -}; +} __packed; struct cvp_hfi_msg_session_hdr_d { u32 size; @@ -417,7 +416,7 @@ struct cvp_hfi_msg_session_op_cfg_packet { struct cvp_hfi_client client_data; u32 stream_idx; u32 op_conf_id; -}; +} __packed; struct cvp_hfi_msg_release_buffer_ref_event_packet { u32 packet_buffer; diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index e6ef20647100..e2096d1cadb3 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -18,11 +18,6 @@ extern struct msm_cvp_drv *cvp_driver; -static int _deprecated_hfi_msg_process(u32 device_id, - struct cvp_hfi_msg_session_hdr *pkt, - struct msm_cvp_cb_info *info, - struct msm_cvp_inst *inst); - static enum cvp_status hfi_map_err_status(u32 hfi_err) { enum cvp_status cvp_err; @@ -443,36 +438,6 @@ retry: } -static int __dme_output_cache_operation(struct cvp_hfi_msg_session_hdr *pkt) -{ - struct cvp_hfi_msg_dme_pkt *dme_pkt; - int rc; - - if (!pkt) { - dprintk(CVP_ERR, "%s: invalid param\n", __func__); - return -EINVAL; - } else if (pkt->size < get_msg_size()) { - dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); - return -E2BIG; - } - - dme_pkt = (struct cvp_hfi_msg_dme_pkt *)pkt; - rc = dma_buf_begin_cpu_access_partial(dme_pkt->statsbuffer.dbuf, - DMA_TO_DEVICE, 0, - dme_pkt->statsbuffer.size); - if (rc) { - dprintk(CVP_ERR, "%s: begin_cpu_access failed\n", __func__); - return rc; - } - rc = dma_buf_end_cpu_access_partial(dme_pkt->statsbuffer.dbuf, - DMA_FROM_DEVICE, 0, - dme_pkt->statsbuffer.size); - if (rc) - dprintk(CVP_ERR, "%s: end_cpu_access failed\n", __func__); - - return rc; -} - static int hfi_process_session_cvp_msg(u32 device_id, struct cvp_hfi_msg_session_hdr *pkt, struct msm_cvp_cb_info *info) @@ -481,6 +446,7 @@ static int hfi_process_session_cvp_msg(u32 device_id, struct msm_cvp_inst *inst = NULL; struct msm_cvp_core *core; void *session_id; + struct cvp_session_queue *sq; if (!pkt) { dprintk(CVP_ERR, "%s: invalid param\n", __func__); @@ -498,29 +464,10 @@ static int hfi_process_session_cvp_msg(u32 device_id, return -EINVAL; } - if (inst->deprecate_bitmask) { - if (pkt->packet_type == HFI_MSG_SESSION_CVP_DME - || pkt->packet_type == HFI_MSG_SESSION_CVP_ICA - || pkt->packet_type == HFI_MSG_SESSION_CVP_FD) { - u64 ktid; - u32 kdata1, kdata2; - - kdata1 = pkt->client_data.kdata1; - kdata2 = pkt->client_data.kdata2; - ktid = ((u64)kdata2 << 32) | kdata1; - - - if (pkt->packet_type == HFI_MSG_SESSION_CVP_DME) - __dme_output_cache_operation(pkt); - - msm_cvp_unmap_buf_cpu(inst, ktid); - - return _deprecated_hfi_msg_process(device_id, - pkt, info, inst); - } - dprintk(CVP_ERR, "Invalid deprecate_bitmask %#x\n", - inst->deprecate_bitmask); - } + if (pkt->client_data.kdata & FENCE_BIT) + sq = &inst->session_queue_fence; + else + sq = &inst->session_queue; sess_msg = kmem_cache_alloc(cvp_driver->msg_cache, GFP_KERNEL); if (sess_msg == NULL) { @@ -535,139 +482,27 @@ static int hfi_process_session_cvp_msg(u32 device_id, __func__, pkt->packet_type, hfi_map_err_status(get_msg_errorcode(pkt)), session_id); - spin_lock(&inst->session_queue.lock); - if (inst->session_queue.msg_count >= MAX_NUM_MSGS_PER_SESSION) { + spin_lock(&sq->lock); + if (sq->msg_count >= MAX_NUM_MSGS_PER_SESSION) { dprintk(CVP_ERR, "Reached session queue size limit\n"); goto error_handle_msg; } - list_add_tail(&sess_msg->node, &inst->session_queue.msgs); - inst->session_queue.msg_count++; - spin_unlock(&inst->session_queue.lock); + list_add_tail(&sess_msg->node, &sq->msgs); + sq->msg_count++; + spin_unlock(&sq->lock); - wake_up_all(&inst->session_queue.wq); + wake_up_all(&sq->wq); info->response_type = HAL_NO_RESP; return 0; error_handle_msg: - spin_unlock(&inst->session_queue.lock); + spin_unlock(&sq->lock); kmem_cache_free(cvp_driver->msg_cache, sess_msg); return -ENOMEM; } -static int hfi_process_session_cvp_dme(u32 device_id, - struct cvp_hfi_msg_session_hdr *pkt, - struct msm_cvp_cb_info *info) -{ - struct msm_cvp_cb_cmd_done cmd_done = {0}; - - if (!pkt) { - dprintk(CVP_ERR, "%s: invalid param\n", __func__); - return -EINVAL; - } else if (pkt->size < get_msg_size()) { - dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); - return -E2BIG; - } - - cmd_done.device_id = device_id; - cmd_done.session_id = (void *)(uintptr_t)get_msg_session_id(pkt); - cmd_done.status = hfi_map_err_status(get_msg_errorcode(pkt)); - cmd_done.size = 0; - - dprintk(CVP_DBG, - "%s: device_id=%d cmd_done.status=%d sessionid=%#x\n", - __func__, device_id, cmd_done.status, cmd_done.session_id); - info->response_type = HAL_SESSION_DME_FRAME_CMD_DONE; - info->response.cmd = cmd_done; - - return 0; -} - -static int hfi_process_session_cvp_ica(u32 device_id, - struct cvp_hfi_msg_session_hdr *pkt, - struct msm_cvp_cb_info *info) -{ - struct msm_cvp_cb_cmd_done cmd_done = {0}; - - if (!pkt) { - dprintk(CVP_ERR, "%s: invalid param\n", __func__); - return -EINVAL; - } else if (pkt->size < get_msg_size()) { - dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); - return -E2BIG; - } - - cmd_done.device_id = device_id; - cmd_done.session_id = (void *)(uintptr_t)get_msg_session_id(pkt); - cmd_done.status = hfi_map_err_status(get_msg_errorcode(pkt)); - cmd_done.size = 0; - - dprintk(CVP_DBG, - "%s: device_id=%d cmd_done.status=%d sessionid=%#x\n", - __func__, device_id, cmd_done.status, cmd_done.session_id); - info->response_type = HAL_SESSION_ICA_FRAME_CMD_DONE; - info->response.cmd = cmd_done; - - return 0; -} - -static int hfi_process_session_cvp_fd(u32 device_id, - struct cvp_hfi_msg_session_hdr *pkt, - struct msm_cvp_cb_info *info) -{ - struct msm_cvp_cb_cmd_done cmd_done = {0}; - - if (!pkt) { - dprintk(CVP_ERR, "%s: invalid param\n", __func__); - return -EINVAL; - } else if (pkt->size < get_msg_size()) { - dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); - return -E2BIG; - } - - cmd_done.device_id = device_id; - cmd_done.session_id = (void *)(uintptr_t)get_msg_session_id(pkt); - cmd_done.status = hfi_map_err_status(get_msg_errorcode(pkt)); - cmd_done.size = 0; - - dprintk(CVP_DBG, - "%s: device_id=%d cmd_done.status=%d sessionid=%#x\n", - __func__, device_id, cmd_done.status, cmd_done.session_id); - info->response_type = HAL_SESSION_FD_FRAME_CMD_DONE; - info->response.cmd = cmd_done; - - return 0; -} - -static int _deprecated_hfi_msg_process(u32 device_id, - struct cvp_hfi_msg_session_hdr *pkt, - struct msm_cvp_cb_info *info, - struct msm_cvp_inst *inst) -{ - if (pkt->packet_type == HFI_MSG_SESSION_CVP_DME) - if (test_bit(DME_BIT_OFFSET, - &inst->deprecate_bitmask)) - return hfi_process_session_cvp_dme( - device_id, (void *)pkt, info); - - if (pkt->packet_type == HFI_MSG_SESSION_CVP_ICA) - if (test_bit(ICA_BIT_OFFSET, - &inst->deprecate_bitmask)) - return hfi_process_session_cvp_ica( - device_id, (void *)pkt, info); - - if (pkt->packet_type == HFI_MSG_SESSION_CVP_FD) - if (test_bit(FD_BIT_OFFSET, - &inst->deprecate_bitmask)) - return hfi_process_session_cvp_fd( - device_id, (void *)pkt, info); - - dprintk(CVP_ERR, "Deprecatd MSG doesn't match bitmask %x %lx\n", - pkt->packet_type, inst->deprecate_bitmask); - return -EINVAL; -} - static void hfi_process_sys_get_prop_image_version( struct cvp_hfi_msg_sys_property_info_packet *pkt) { diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index e87f392c1c50..51c2f462a1ce 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -3,9 +3,13 @@ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ +#include +#include +#include +#include +#include #include "msm_cvp.h" #include "cvp_hfi.h" -#include #include "cvp_core_hfi.h" #include "cvp_hfi_helper.h" @@ -186,9 +190,8 @@ static int msm_cvp_map_buf_dsp(struct msm_cvp_inst *inst, } cbuf = kmem_cache_zalloc(cvp_driver->internal_buf_cache, GFP_KERNEL); - if (!cbuf) { + if (!cbuf) return -ENOMEM; - } memcpy(&cbuf->buf, buf, sizeof(struct cvp_kmd_buffer)); cbuf->smem.buffer_type = get_hal_buftype(__func__, buf->type); @@ -578,7 +581,9 @@ void msm_cvp_unmap_buf_cpu(struct msm_cvp_inst *inst, u64 ktid) return; } + ktid &= (FENCE_BIT - 1); dprintk(CVP_DBG, "%s: unmap frame %llu\n", __func__, ktid); + found = false; mutex_lock(&inst->frames.lock); list_for_each_entry_safe(frame, dummy1, &inst->frames.list, list) { @@ -607,13 +612,13 @@ void msm_cvp_unmap_buf_cpu(struct msm_cvp_inst *inst, u64 ktid) } } -static bool _cvp_msg_pending(struct msm_cvp_inst *inst, - struct cvp_session_queue *sq, - struct cvp_session_msg **msg) +static bool cvp_msg_pending(struct cvp_session_queue *sq, + struct cvp_session_msg **msg, u64 *ktid) { - struct cvp_session_msg *mptr = NULL; + struct cvp_session_msg *mptr, *dummy; bool result = false; + mptr = NULL; spin_lock(&sq->lock); if (sq->state != QUEUE_ACTIVE) { /* The session is being deleted */ @@ -623,27 +628,77 @@ static bool _cvp_msg_pending(struct msm_cvp_inst *inst, } result = list_empty(&sq->msgs); if (!result) { - mptr = - list_first_entry(&sq->msgs, struct cvp_session_msg, node); - list_del_init(&mptr->node); - sq->msg_count--; + if (!ktid) { + mptr = + list_first_entry(&sq->msgs, struct cvp_session_msg, + node); + list_del_init(&mptr->node); + sq->msg_count--; + } else { + result = true; + list_for_each_entry_safe(mptr, dummy, &sq->msgs, node) { + if (*ktid == mptr->pkt.client_data.kdata) { + list_del_init(&mptr->node); + sq->msg_count--; + result = false; + break; + } + } + if (result) + mptr = NULL; + } } spin_unlock(&sq->lock); *msg = mptr; return !result; } +static int cvp_wait_process_message(struct msm_cvp_inst *inst, + struct cvp_session_queue *sq, u64 *ktid, + unsigned long timeout, + struct cvp_kmd_hfi_packet *out) +{ + struct cvp_session_msg *msg = NULL; + int rc = 0; + + if (wait_event_timeout(sq->wq, + cvp_msg_pending(sq, &msg, ktid), timeout) == 0) { + dprintk(CVP_WARN, "session queue wait timeout\n"); + rc = -ETIMEDOUT; + goto exit; + } + + if (msg == NULL) { + dprintk(CVP_WARN, "%s: queue state %d, msg cnt %d\n", __func__, + sq->state, sq->msg_count); + + if (inst->state >= MSM_CVP_CLOSE_DONE || + sq->state != QUEUE_ACTIVE) { + rc = -ECONNRESET; + goto exit; + } + + msm_cvp_comm_kill_session(inst); + goto exit; + } + + msm_cvp_unmap_buf_cpu(inst, msg->pkt.client_data.kdata); + if (out) + memcpy(out, &msg->pkt, sizeof(struct cvp_hfi_msg_session_hdr)); + + kmem_cache_free(cvp_driver->msg_cache, msg); + +exit: + return rc; +} static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst, struct cvp_kmd_hfi_packet *out_pkt) { unsigned long wait_time; - struct cvp_session_msg *msg = NULL; struct cvp_session_queue *sq; - struct cvp_kmd_session_control *sc; struct msm_cvp_inst *s; int rc = 0; - u32 version; if (!inst) { dprintk(CVP_ERR, "%s invalid session\n", __func__); @@ -655,51 +710,11 @@ static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst, return -ECONNRESET; s->cur_cmd_type = CVP_KMD_RECEIVE_MSG_PKT; - sq = &inst->session_queue; - sc = (struct cvp_kmd_session_control *)out_pkt; - wait_time = msecs_to_jiffies(CVP_MAX_WAIT_TIME); + sq = &inst->session_queue; - if (wait_event_timeout(sq->wq, - _cvp_msg_pending(inst, sq, &msg), wait_time) == 0) { - dprintk(CVP_WARN, "session queue wait timeout\n"); - rc = -ETIMEDOUT; - goto exit; - } + rc = cvp_wait_process_message(inst, sq, NULL, wait_time, out_pkt); - version = (get_hfi_version() & HFI_VERSION_MINOR_MASK) - >> HFI_VERSION_MINOR_SHIFT; - - if (msg == NULL) { - dprintk(CVP_WARN, - "%s: session deleted, queue state %d, msg cnt %d\n", - __func__, inst->session_queue.state, - inst->session_queue.msg_count); - - if (inst->state >= MSM_CVP_CLOSE_DONE || - sq->state != QUEUE_ACTIVE) { - rc = -ECONNRESET; - goto exit; - } - - msm_cvp_comm_kill_session(inst); - } else { - if (version >= 1) { - u64 ktid; - u32 kdata1, kdata2; - - kdata1 = msg->pkt.client_data.kdata1; - kdata2 = msg->pkt.client_data.kdata2; - ktid = ((u64)kdata2 << 32) | kdata1; - msm_cvp_unmap_buf_cpu(inst, ktid); - } - - memcpy(out_pkt, &msg->pkt, - sizeof(struct cvp_hfi_msg_session_hdr)); - kmem_cache_free(cvp_driver->msg_cache, msg); - } - -exit: s->cur_cmd_type = 0; cvp_put_inst(inst); return rc; @@ -775,8 +790,8 @@ static int msm_cvp_map_buf(struct msm_cvp_inst *inst, cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; ktid = atomic64_inc_return(&inst->core->kernel_trans_id); - cmd_hdr->client_data.kdata1 = (u32)ktid; - cmd_hdr->client_data.kdata2 = (u32)(ktid >> 32); + ktid &= (FENCE_BIT - 1); + cmd_hdr->client_data.kdata = ktid; frame = kmem_cache_zalloc(cvp_driver->frame_cache, GFP_KERNEL); if (!frame) @@ -993,6 +1008,36 @@ exit: return rc; } +static bool cvp_fence_wait(struct cvp_fence_queue *q, + struct msm_cvp_fence_thread_data **fence, + enum queue_state *state) +{ + struct msm_cvp_fence_thread_data *f; + + *fence = NULL; + spin_lock(&q->lock); + *state = q->state; + if (*state != QUEUE_ACTIVE) { + spin_unlock(&q->lock); + return true; + } + + if (list_empty(&q->wait_list)) { + spin_unlock(&q->lock); + return false; + } + + f = list_first_entry(&q->wait_list, + struct msm_cvp_fence_thread_data, list); + list_del_init(&f->list); + list_add_tail(&q->sched_list, &f->list); + + spin_unlock(&q->lock); + *fence = f; + + return true; +} + #define CVP_FENCE_RUN 0x100 static int msm_cvp_thread_fence_run(void *data) { @@ -1004,22 +1049,26 @@ static int msm_cvp_thread_fence_run(void *data) struct cvp_kmd_hfi_fence_packet *in_fence_pkt; struct cvp_kmd_hfi_packet *in_pkt; struct msm_cvp_inst *inst; + struct sched_param param = {.sched_priority = 64 }; int *fence; int ica_enabled = 0; int pkt_idx; int synx_state = SYNX_STATE_SIGNALED_SUCCESS; + u64 ktid; + struct cvp_hfi_cmd_session_hdr *cmd_hdr; + + sched_setscheduler(current, SCHED_FIFO, ¶m); if (!data) { dprintk(CVP_ERR, "%s Wrong input data %pK\n", __func__, data); - do_exit(-EINVAL); + return -EINVAL; } fence_thread_data = data; inst = fence_thread_data->inst; if (!inst) { dprintk(CVP_ERR, "%s Wrong inst %pK\n", __func__, inst); - rc = -EINVAL; - return rc; + return -EINVAL; } inst->cur_cmd_type = CVP_FENCE_RUN; in_fence_pkt = (struct cvp_kmd_hfi_fence_packet *) @@ -1037,6 +1086,8 @@ static int msm_cvp_thread_fence_run(void *data) fence = (int *)(in_fence_pkt->fence_data); hdev = inst->core->device; + cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; + ktid = cmd_hdr->client_data.kdata; //wait on synx before signaling HFI switch (cvp_hfi_defs[pkt_idx].type) { @@ -1078,7 +1129,6 @@ static int msm_cvp_thread_fence_run(void *data) } if (synx_state != SYNX_STATE_SIGNALED_ERROR) { - mutex_lock(&inst->fence_lock); rc = call_hfi_op(hdev, session_send, (void *)inst->session, in_pkt); if (rc) { @@ -1089,15 +1139,15 @@ static int msm_cvp_thread_fence_run(void *data) synx_state = SYNX_STATE_SIGNALED_ERROR; } - rc = wait_for_sess_signal_receipt_fence(inst, - HAL_SESSION_DME_FRAME_CMD_DONE); + rc = cvp_wait_process_message(inst, + &inst->session_queue_fence, + &ktid, timeout_ms, NULL); if (rc) { dprintk(CVP_ERR, "%s: wait for signal failed, rc %d\n", __func__, rc); synx_state = SYNX_STATE_SIGNALED_ERROR; } - mutex_unlock(&inst->fence_lock); } if (ica_enabled) { @@ -1142,82 +1192,6 @@ static int msm_cvp_thread_fence_run(void *data) } break; } - case HFI_CMD_SESSION_CVP_ICA_FRAME: - { - for (i = 0; i < cvp_hfi_defs[pkt_idx].buf_num-1; i++) { - if (fence[(i<<1)]) { - rc = synx_import(fence[(i<<1)], - fence[((i<<1)+1)], &synx_obj); - if (rc) { - dprintk(CVP_ERR, - "%s: synx_import failed\n", - __func__); - goto exit; - } - rc = synx_wait(synx_obj, timeout_ms); - if (rc) { - dprintk(CVP_ERR, - "%s: synx_wait failed\n", - __func__); - goto exit; - } - rc = synx_release(synx_obj); - if (rc) { - dprintk(CVP_ERR, - "%s: synx_release failed\n", - __func__); - goto exit; - } - if (i == 0) { - /* - * Increase loop count to skip fence - * waiting on output corrected image. - */ - i = i+1; - } - } - } - - mutex_lock(&inst->fence_lock); - rc = call_hfi_op(hdev, session_send, - (void *)inst->session, in_pkt); - if (rc) { - dprintk(CVP_ERR, - "%s: Failed in call_hfi_op %d, %x\n", - __func__, in_pkt->pkt_data[0], - in_pkt->pkt_data[1]); - synx_state = SYNX_STATE_SIGNALED_ERROR; - } - - if (synx_state != SYNX_STATE_SIGNALED_ERROR) { - rc = wait_for_sess_signal_receipt_fence(inst, - HAL_SESSION_ICA_FRAME_CMD_DONE); - if (rc) { - dprintk(CVP_ERR, - "%s: wait for signal failed, rc %d\n", - __func__, rc); - synx_state = SYNX_STATE_SIGNALED_ERROR; - } - } - mutex_unlock(&inst->fence_lock); - - rc = synx_import(fence[2], fence[3], &synx_obj); - if (rc) { - dprintk(CVP_ERR, "%s: synx_import failed\n", __func__); - goto exit; - } - rc = synx_signal(synx_obj, synx_state); - if (rc) { - dprintk(CVP_ERR, "%s: synx_signal failed\n", __func__); - goto exit; - } - rc = synx_release(synx_obj); - if (rc) { - dprintk(CVP_ERR, "%s: synx_release failed\n", __func__); - goto exit; - } - break; - } case HFI_CMD_SESSION_CVP_FD_FRAME: { int in_fence_num = fence[0]; @@ -1251,7 +1225,6 @@ static int msm_cvp_thread_fence_run(void *data) } } - mutex_lock(&inst->fence_lock); rc = call_hfi_op(hdev, session_send, (void *)inst->session, in_pkt); if (rc) { @@ -1262,17 +1235,14 @@ static int msm_cvp_thread_fence_run(void *data) synx_state = SYNX_STATE_SIGNALED_ERROR; } - if (synx_state != SYNX_STATE_SIGNALED_ERROR) { - rc = wait_for_sess_signal_receipt_fence(inst, - HAL_SESSION_FD_FRAME_CMD_DONE); - if (rc) { - dprintk(CVP_ERR, - "%s: wait for signal failed, rc %d\n", - __func__, rc); - synx_state = SYNX_STATE_SIGNALED_ERROR; - } + rc = cvp_wait_process_message(inst, &inst->session_queue_fence, + &ktid, timeout_ms, NULL); + if (rc) { + dprintk(CVP_ERR, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + synx_state = SYNX_STATE_SIGNALED_ERROR; } - mutex_unlock(&inst->fence_lock); for (i = start_out; i < start_out + out_fence_num; i++) { if (fence[(i<<1)]) { @@ -1313,24 +1283,62 @@ static int msm_cvp_thread_fence_run(void *data) exit: kmem_cache_free(cvp_driver->fence_data_cache, fence_thread_data); inst->cur_cmd_type = 0; + return rc; +} + +static int cvp_fence_thread(void *data) +{ + int rc = 0; + struct msm_cvp_inst *inst; + struct cvp_fence_queue *q; + enum queue_state state; + struct msm_cvp_fence_thread_data *fence_data; + + dprintk(CVP_DBG, "Enter %s\n", current->comm); + + inst = (struct msm_cvp_inst *)data; + if (!inst || !inst->core || !inst->core->device) { + dprintk(CVP_ERR, "%s invalid inst %pK\n", current->comm, inst); + rc = -EINVAL; + goto exit; + } + + q = &inst->fence_cmd_queue; + +wait: + dprintk(CVP_DBG, "%s starts wait\n", current->comm); + + fence_data = NULL; + wait_event_interruptible(q->wq, cvp_fence_wait(q, &fence_data, &state)); + if (state != QUEUE_ACTIVE) + goto exit; + + if (!fence_data) + goto wait; + + rc = msm_cvp_thread_fence_run(fence_data); + if (rc) + goto exit; + + goto wait; +exit: + dprintk(CVP_DBG, "%s exit\n", current->comm); cvp_put_inst(inst); do_exit(rc); } -static int msm_cvp_session_process_hfi_fence( - struct msm_cvp_inst *inst, - struct cvp_kmd_arg *arg) +static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, + struct cvp_kmd_arg *arg) { - static int thread_num; - struct task_struct *thread; int rc = 0; - char thread_fence_name[32]; int pkt_idx; struct cvp_kmd_hfi_packet *in_pkt; unsigned int signal, offset, buf_num, in_offset, in_buf_num; struct msm_cvp_inst *s; unsigned int max_buf_num; struct msm_cvp_fence_thread_data *fence_thread_data; + struct cvp_fence_queue *q; + struct cvp_hfi_cmd_session_hdr *cmd_hdr; dprintk(CVP_DBG, "%s: Enter inst = %#x", __func__, inst); @@ -1389,23 +1397,22 @@ static int msm_cvp_session_process_hfi_fence( if (rc) goto free_and_exit; - thread_num = thread_num + 1; + cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; + cmd_hdr->client_data.kdata |= FENCE_BIT; fence_thread_data->inst = inst; fence_thread_data->device_id = (unsigned int)inst->core->id; memcpy(&fence_thread_data->in_fence_pkt, &arg->data.hfi_fence_pkt, sizeof(struct cvp_kmd_hfi_fence_packet)); fence_thread_data->arg_type = arg->type; - snprintf(thread_fence_name, sizeof(thread_fence_name), - "thread_fence_%d", thread_num); - thread = kthread_run(msm_cvp_thread_fence_run, - fence_thread_data, thread_fence_name); - if (!thread) { - dprintk(CVP_ERR, "%s fail to create kthread\n", __func__); - rc = -ECHILD; - goto free_and_exit; - } - return 0; + q = &inst->fence_cmd_queue; + spin_lock(&q->lock); + list_add_tail(&fence_thread_data->list, &q->wait_list); + spin_unlock(&q->lock); + + wake_up(&inst->fence_cmd_queue.wq); + + goto exit; free_and_exit: kmem_cache_free(cvp_driver->fence_data_cache, fence_thread_data); @@ -1415,38 +1422,6 @@ exit: return rc; } -static int msm_cvp_session_cvp_dfs_frame_response( - struct msm_cvp_inst *inst, - struct cvp_kmd_hfi_packet *dfs_frame) -{ - dprintk(CVP_ERR, "Deprecated system call: DFS_CMD_RESPONSE\n"); - return -EINVAL; -} - -static int msm_cvp_session_cvp_dme_frame_response( - struct msm_cvp_inst *inst, - struct cvp_kmd_hfi_packet *dme_frame) -{ - dprintk(CVP_ERR, "Deprecated system call: DME_CMD_RESPONSE\n"); - return -EINVAL; -} - -static int msm_cvp_session_cvp_persist_response( - struct msm_cvp_inst *inst, - struct cvp_kmd_hfi_packet *pbuf_cmd) -{ - dprintk(CVP_ERR, "Deprecated system call: PERSIST_CMD_RESPONSE\n"); - return -EINVAL; -} - -static int msm_cvp_send_cmd(struct msm_cvp_inst *inst, - struct cvp_kmd_send_cmd *send_cmd) -{ - dprintk(CVP_ERR, "Deprecated system call: cvp_send_cmd\n"); - - return 0; -} - static inline int div_by_1dot5(unsigned int a) { unsigned long i = a << 1; @@ -1796,8 +1771,8 @@ static int msm_cvp_request_power(struct msm_cvp_inst *inst, } static int msm_cvp_update_power(struct msm_cvp_inst *inst) - -{ int rc = 0; +{ + int rc = 0; struct msm_cvp_core *core; struct msm_cvp_inst *s; @@ -1872,9 +1847,8 @@ static int msm_cvp_unregister_buffer(struct msm_cvp_inst *inst, return -EINVAL; } - if (!buf->index) { + if (!buf->index) return 0; - } s = cvp_get_inst_validate(inst->core, inst); if (!s) @@ -1937,6 +1911,79 @@ static int session_state_check_init(struct msm_cvp_inst *inst) return msm_cvp_session_create(inst); } +static int cvp_fence_thread_start(struct msm_cvp_inst *inst) +{ + u32 tnum = 0; + u32 i = 0; + int rc = 0; + char tname[16]; + struct task_struct *thread; + struct cvp_fence_queue *q; + struct cvp_session_queue *sq; + + if (!inst->prop.fthread_nr) + return 0; + + q = &inst->fence_cmd_queue; + spin_lock(&q->lock); + q->state = QUEUE_ACTIVE; + spin_unlock(&q->lock); + + for (i = 0; i < inst->prop.fthread_nr; ++i) { + if (!cvp_get_inst_validate(inst->core, inst)) { + rc = -ECONNRESET; + goto exit; + } + + snprintf(tname, sizeof(tname), "fthread_%d", tnum++); + thread = kthread_run(cvp_fence_thread, inst, tname); + if (!thread) { + dprintk(CVP_ERR, "%s create %s fail", __func__, tname); + rc = -ECHILD; + goto exit; + } + } + + sq = &inst->session_queue_fence; + spin_lock(&sq->lock); + sq->state = QUEUE_ACTIVE; + spin_unlock(&sq->lock); + +exit: + if (rc) { + spin_lock(&q->lock); + q->state = QUEUE_STOP; + spin_unlock(&q->lock); + wake_up_all(&q->wq); + } + return rc; +} + +static int cvp_fence_thread_stop(struct msm_cvp_inst *inst) +{ + struct cvp_fence_queue *q; + struct cvp_session_queue *sq; + + if (!inst->prop.fthread_nr) + return 0; + + q = &inst->fence_cmd_queue; + + spin_lock(&q->lock); + q->state = QUEUE_STOP; + spin_unlock(&q->lock); + + sq = &inst->session_queue_fence; + spin_lock(&sq->lock); + sq->state = QUEUE_STOP; + spin_unlock(&sq->lock); + + wake_up_all(&q->wq); + wake_up_all(&sq->wq); + + return 0; +} + static int msm_cvp_session_start(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) { @@ -1953,7 +2000,7 @@ static int msm_cvp_session_start(struct msm_cvp_inst *inst, sq->state = QUEUE_ACTIVE; spin_unlock(&sq->lock); - return 0; + return cvp_fence_thread_start(inst); } static int msm_cvp_session_stop(struct msm_cvp_inst *inst, @@ -1978,7 +2025,7 @@ static int msm_cvp_session_stop(struct msm_cvp_inst *inst, wake_up_all(&inst->session_queue.wq); - return 0; + return cvp_fence_thread_stop(inst); } static int msm_cvp_session_ctrl(struct msm_cvp_inst *inst, @@ -2201,14 +2248,6 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) rc = msm_cvp_unregister_buffer(inst, buf); break; } - case CVP_KMD_HFI_SEND_CMD: - { - struct cvp_kmd_send_cmd *send_cmd = - (struct cvp_kmd_send_cmd *)&arg->data.send_cmd; - - rc = msm_cvp_send_cmd(inst, send_cmd); - break; - } case CVP_KMD_RECEIVE_MSG_PKT: { struct cvp_kmd_hfi_packet *out_pkt = @@ -2217,12 +2256,6 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) break; } case CVP_KMD_SEND_CMD_PKT: - case CVP_KMD_HFI_DFS_CONFIG_CMD: - case CVP_KMD_HFI_DFS_FRAME_CMD: - case CVP_KMD_HFI_DME_CONFIG_CMD: - case CVP_KMD_HFI_DME_FRAME_CMD: - case CVP_KMD_HFI_FD_FRAME_CMD: - case CVP_KMD_HFI_PERSIST_CMD: { struct cvp_kmd_hfi_packet *in_pkt = (struct cvp_kmd_hfi_packet *)&arg->data.hfi_pkt; @@ -2231,31 +2264,6 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) arg->buf_offset, arg->buf_num); break; } - case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: - { - struct cvp_kmd_hfi_packet *dfs_frame = - (struct cvp_kmd_hfi_packet *)&arg->data.hfi_pkt; - - rc = msm_cvp_session_cvp_dfs_frame_response(inst, dfs_frame); - break; - } - case CVP_KMD_HFI_DME_FRAME_CMD_RESPONSE: - { - struct cvp_kmd_hfi_packet *dme_frame = - (struct cvp_kmd_hfi_packet *)&arg->data.hfi_pkt; - - rc = msm_cvp_session_cvp_dme_frame_response(inst, dme_frame); - break; - } - case CVP_KMD_HFI_PERSIST_CMD_RESPONSE: - { - struct cvp_kmd_hfi_packet *pbuf_cmd = - (struct cvp_kmd_hfi_packet *)&arg->data.hfi_pkt; - - rc = msm_cvp_session_cvp_persist_response(inst, pbuf_cmd); - break; - } - case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: case CVP_KMD_SEND_FENCE_CMD_PKT: { rc = msm_cvp_session_process_hfi_fence(inst, arg); @@ -2388,6 +2396,7 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst) inst->prop.priority = 0; inst->prop.is_secure = 0; inst->prop.dsp_mask = 0; + inst->prop.fthread_nr = 2; return rc; } diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c index f05856013ec3..ce1950f32b61 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c @@ -406,54 +406,6 @@ int wait_for_sess_signal_receipt(struct msm_cvp_inst *inst, return rc; } -int wait_for_sess_signal_receipt_fence(struct msm_cvp_inst *inst, - enum hal_command_response cmd) -{ - int rc = 0; - struct cvp_hfi_device *hdev; - int retry = FENCE_WAIT_SIGNAL_RETRY_TIMES; - - if (!IS_HAL_SESSION_CMD(cmd)) { - dprintk(CVP_ERR, "Invalid inst cmd response: %d\n", cmd); - return -EINVAL; - } - hdev = (struct cvp_hfi_device *)(inst->core->device); - - while (retry) { - rc = wait_for_completion_timeout( - &inst->completions[SESSION_MSG_INDEX(cmd)], - msecs_to_jiffies(FENCE_WAIT_SIGNAL_TIMEOUT)); - if (!rc) { - enum cvp_event_t event; - unsigned long flags = 0; - - spin_lock_irqsave(&inst->event_handler.lock, flags); - event = inst->event_handler.event; - spin_unlock_irqrestore( - &inst->event_handler.lock, flags); - if (event == CVP_SSR_EVENT) { - dprintk(CVP_WARN, "%s: SSR triggered\n", - __func__); - return -ECONNRESET; - } - --retry; - } else { - rc = 0; - break; - } - } - - if (!retry) { - dprintk(CVP_WARN, "Wait interrupted or timed out: %d\n", - SESSION_MSG_INDEX(cmd)); - call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); - dump_hfi_queue(hdev->hfi_device_data); - rc = -EIO; - } - - return rc; -} - static int wait_for_state(struct msm_cvp_inst *inst, enum instance_state flipped_state, enum instance_state desired_state, @@ -774,13 +726,6 @@ static void handle_session_close(enum hal_command_response cmd, void *data) cvp_put_inst(inst); } -static void handle_operation_config(enum hal_command_response cmd, void *data) -{ - dprintk(CVP_ERR, - "%s: is called\n", - __func__); -} - void cvp_handle_cmd_response(enum hal_command_response cmd, void *data) { dprintk(CVP_DBG, "Command response = %d\n", cmd); @@ -794,9 +739,6 @@ void cvp_handle_cmd_response(enum hal_command_response cmd, void *data) case HAL_SESSION_INIT_DONE: handle_session_init_done(cmd, data); break; - case HAL_SESSION_CVP_OPERATION_CONFIG: - handle_operation_config(cmd, data); - break; case HAL_SESSION_RELEASE_RESOURCE_DONE: handle_release_res_done(cmd, data); break; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.h b/drivers/media/platform/msm/cvp/msm_cvp_common.h index 2322a98985d0..99dd3fdc90ae 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.h @@ -41,8 +41,6 @@ void print_cvp_buffer(u32 tag, const char *str, struct msm_cvp_internal_buffer *cbuf); int wait_for_sess_signal_receipt(struct msm_cvp_inst *inst, enum hal_command_response cmd); -int wait_for_sess_signal_receipt_fence(struct msm_cvp_inst *inst, - enum hal_command_response cmd); int cvp_comm_set_arp_buffers(struct msm_cvp_inst *inst); int cvp_comm_release_persist_buffers(struct msm_cvp_inst *inst); void print_client_buffer(u32 tag, const char *str, diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index a4a86def1616..a4f02247995a 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -221,7 +221,7 @@ static bool msm_cvp_check_for_inst_overload(struct msm_cvp_core *core) return overload; } -static int _init_session_queue(struct msm_cvp_inst *inst) +static int __init_session_queue(struct msm_cvp_inst *inst) { spin_lock_init(&inst->session_queue.lock); INIT_LIST_HEAD(&inst->session_queue.msgs); @@ -231,6 +231,21 @@ static int _init_session_queue(struct msm_cvp_inst *inst) return 0; } +static void __init_fence_queue(struct msm_cvp_inst *inst) +{ + spin_lock_init(&inst->fence_cmd_queue.lock); + INIT_LIST_HEAD(&inst->fence_cmd_queue.wait_list); + INIT_LIST_HEAD(&inst->fence_cmd_queue.sched_list); + init_waitqueue_head(&inst->fence_cmd_queue.wq); + inst->fence_cmd_queue.state = QUEUE_ACTIVE; + + spin_lock_init(&inst->session_queue_fence.lock); + INIT_LIST_HEAD(&inst->session_queue_fence.msgs); + inst->session_queue_fence.msg_count = 0; + init_waitqueue_head(&inst->session_queue_fence.wq); + inst->session_queue_fence.state = QUEUE_ACTIVE; +} + static void _deinit_session_queue(struct msm_cvp_inst *inst) { struct cvp_session_msg *msg, *tmpmsg; @@ -291,7 +306,6 @@ void *msm_cvp_open(int core_id, int session_type) pr_info(CVP_DBG_TAG "Opening cvp instance: %pK\n", "info", inst); mutex_init(&inst->sync_lock); mutex_init(&inst->lock); - mutex_init(&inst->fence_lock); spin_lock_init(&inst->event_handler.lock); INIT_MSM_CVP_LIST(&inst->persistbufs); @@ -314,7 +328,6 @@ void *msm_cvp_open(int core_id, int session_type) inst->clk_data.sys_cache_bw = 0; inst->clk_data.bitrate = 0; inst->clk_data.core_id = 0; - inst->deprecate_bitmask = 0; for (i = SESSION_MSG_INDEX(SESSION_MSG_START); i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { @@ -327,7 +340,9 @@ void *msm_cvp_open(int core_id, int session_type) list_add_tail(&inst->list, &core->instances); mutex_unlock(&core->lock); - rc = _init_session_queue(inst); + __init_fence_queue(inst); + + rc = __init_session_queue(inst); if (rc) goto fail_init; @@ -349,7 +364,6 @@ fail_init: mutex_unlock(&core->lock); mutex_destroy(&inst->sync_lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->fence_lock); DEINIT_MSM_CVP_LIST(&inst->persistbufs); DEINIT_MSM_CVP_LIST(&inst->cvpcpubufs); @@ -402,7 +416,6 @@ int msm_cvp_destroy(struct msm_cvp_inst *inst) mutex_destroy(&inst->sync_lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->fence_lock); msm_cvp_debugfs_deinit_inst(inst); _deinit_session_queue(inst); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h index 0a27a827be3e..2f522143a044 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h @@ -24,6 +24,7 @@ #include #include #include "cvp_hfi_api.h" +#include #define MAX_SUPPORTED_INSTANCES 16 #define MAX_NAME_LENGTH 64 @@ -31,6 +32,11 @@ #define MAX_DSP_INIT_ATTEMPTS 16 #define FENCE_WAIT_SIGNAL_TIMEOUT 100 #define FENCE_WAIT_SIGNAL_RETRY_TIMES 20 +#define FENCE_BIT (1ULL << 63) + +#define FENCE_DME_ICA_ENABLED_IDX 0 +#define FENCE_DME_DS_IDX 1 +#define FENCE_DME_OUTPUT_IDX 7 #define SYS_MSG_START HAL_SYS_INIT_DONE #define SYS_MSG_END HAL_SYS_ERROR @@ -251,6 +257,7 @@ struct cvp_session_prop { u32 priority; u32 is_secure; u32 dsp_mask; + u32 fthread_nr; u32 fdu_cycles; u32 od_cycles; u32 mpu_cycles; @@ -267,6 +274,14 @@ struct cvp_session_prop { u32 ddr_op_cache; }; +struct cvp_fence_queue { + spinlock_t lock; + enum queue_state state; + struct list_head wait_list; + wait_queue_head_t wq; + struct list_head sched_list; +}; + enum cvp_event_t { CVP_NO_EVENT, CVP_SSR_EVENT = 1, @@ -317,6 +332,7 @@ struct msm_cvp_inst { struct msm_cvp_core *core; enum session_type session_type; struct cvp_session_queue session_queue; + struct cvp_session_queue session_queue_fence; struct cvp_session_event event_handler; void *session; enum instance_state state; @@ -332,14 +348,14 @@ struct msm_cvp_inst { enum msm_cvp_modes flags; struct msm_cvp_capability capability; struct kref kref; - unsigned long deprecate_bitmask; struct cvp_kmd_request_power power; struct cvp_session_prop prop; u32 cur_cmd_type; - struct mutex fence_lock; + struct cvp_fence_queue fence_cmd_queue; }; struct msm_cvp_fence_thread_data { + struct list_head list; struct msm_cvp_inst *inst; unsigned int device_id; struct cvp_kmd_hfi_fence_packet in_fence_pkt; @@ -352,13 +368,6 @@ void cvp_handle_cmd_response(enum hal_command_response cmd, void *data); int msm_cvp_trigger_ssr(struct msm_cvp_core *core, enum hal_ssr_trigger_type type); int msm_cvp_noc_error_info(struct msm_cvp_core *core); -void msm_cvp_queue_v4l2_event(struct msm_cvp_inst *inst, int event_type); - -enum msm_cvp_flags { - MSM_CVP_FLAG_DEFERRED = BIT(0), - MSM_CVP_FLAG_RBR_PENDING = BIT(1), - MSM_CVP_FLAG_QUEUED = BIT(2), -}; struct msm_cvp_internal_buffer { struct list_head list; diff --git a/drivers/media/platform/msm/cvp/msm_v4l2_private.c b/drivers/media/platform/msm/cvp/msm_v4l2_private.c index a3e65a14a0fe..79b94f5e3605 100644 --- a/drivers/media/platform/msm/cvp/msm_v4l2_private.c +++ b/drivers/media/platform/msm/cvp/msm_v4l2_private.c @@ -165,37 +165,6 @@ static int _copy_sysprop_to_user(struct cvp_kmd_arg *kp, } -static void _set_deprecate_bitmask(struct cvp_kmd_arg *kp, - struct msm_cvp_inst *inst) -{ - dprintk(CVP_INFO, "%s: kp->type = %#x\n", __func__, kp->type); - - switch (kp->type) { - case CVP_KMD_HFI_DFS_FRAME_CMD: - { - set_bit(DFS_BIT_OFFSET, &inst->deprecate_bitmask); - break; - } - case CVP_KMD_HFI_DME_FRAME_CMD: - { - set_bit(DME_BIT_OFFSET, &inst->deprecate_bitmask); - break; - } - case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: - { - set_bit(DME_BIT_OFFSET, &inst->deprecate_bitmask); - break; - } - case CVP_KMD_HFI_FD_FRAME_CMD: - { - set_bit(FD_BIT_OFFSET, &inst->deprecate_bitmask); - break; - } - default: - break; - } -} - static void print_hfi_short(struct cvp_kmd_arg __user *up) { struct cvp_kmd_hfi_packet *pkt; @@ -262,8 +231,6 @@ static int convert_from_user(struct cvp_kmd_arg *kp, if (get_user(kp->type, &up->type)) return -EFAULT; - _set_deprecate_bitmask(kp, inst); - if (get_user(kp->buf_offset, &up->buf_offset) || get_user(kp->buf_num, &up->buf_num)) return -EFAULT; @@ -336,27 +303,7 @@ static int convert_from_user(struct cvp_kmd_arg *kp, return -EFAULT; break; } - case CVP_KMD_HFI_SEND_CMD: - { - struct cvp_kmd_send_cmd *k, *u; - - k = &kp->data.send_cmd; - u = &up->data.send_cmd; - if (get_user(k->cmd_address_fd, &u->cmd_address_fd) || - get_user(k->cmd_size, &u->cmd_size)) - return -EFAULT; - for (i = 0; i < 10; i++) - if (get_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; - break; - } case CVP_KMD_SEND_CMD_PKT: - case CVP_KMD_HFI_DFS_CONFIG_CMD: - case CVP_KMD_HFI_DFS_FRAME_CMD: - case CVP_KMD_HFI_DME_CONFIG_CMD: - case CVP_KMD_HFI_DME_FRAME_CMD: - case CVP_KMD_HFI_PERSIST_CMD: - case CVP_KMD_HFI_FD_FRAME_CMD: { if (_get_pkt_hdr_from_user(up, &pkt_hdr)) { dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n", @@ -368,7 +315,6 @@ static int convert_from_user(struct cvp_kmd_arg *kp, break; } case CVP_KMD_SEND_FENCE_CMD_PKT: - case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: { if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr)) { dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n", @@ -387,14 +333,9 @@ static int convert_from_user(struct cvp_kmd_arg *kp, return -EFAULT; } - set_feature_bitmask(pkt_idx, &inst->deprecate_bitmask); - rc = _copy_fence_pkt_from_user(kp, up, (pkt_hdr.size >> 2)); break; } - case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: - case CVP_KMD_HFI_DME_FRAME_CMD_RESPONSE: - case CVP_KMD_HFI_PERSIST_CMD_RESPONSE: case CVP_KMD_RECEIVE_MSG_PKT: break; case CVP_KMD_SESSION_CONTROL: @@ -529,33 +470,7 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) return -EFAULT; break; } - case CVP_KMD_HFI_SEND_CMD: - { - struct cvp_kmd_send_cmd *k, *u; - - dprintk(CVP_DBG, "%s: CVP_KMD_HFI_SEND_CMD\n", - __func__); - - k = &kp->data.send_cmd; - u = &up->data.send_cmd; - if (put_user(k->cmd_address_fd, &u->cmd_address_fd) || - put_user(k->cmd_size, &u->cmd_size)) - return -EFAULT; - for (i = 0; i < 10; i++) - if (put_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; - break; - } case CVP_KMD_SEND_CMD_PKT: - case CVP_KMD_HFI_DFS_CONFIG_CMD: - case CVP_KMD_HFI_DFS_FRAME_CMD: - case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: - case CVP_KMD_HFI_DME_CONFIG_CMD: - case CVP_KMD_HFI_DME_FRAME_CMD: - case CVP_KMD_HFI_DME_FRAME_CMD_RESPONSE: - case CVP_KMD_HFI_PERSIST_CMD: - case CVP_KMD_HFI_PERSIST_CMD_RESPONSE: - case CVP_KMD_HFI_FD_FRAME_CMD: { if (_get_pkt_hdr_from_user(up, &pkt_hdr)) return -EFAULT; @@ -566,7 +481,6 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) break; } case CVP_KMD_SEND_FENCE_CMD_PKT: - case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: { if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr)) return -EFAULT; diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index cb027ed1f8c3..73c7da07221f 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/main.c b/drivers/net/wireless/cnss2/main.c index 8c1cdd4bb656..8e841996967a 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -19,6 +19,11 @@ #include "bus.h" #include "debug.h" #include "genl.h" +#include +static u32 fw_version; +static u32 fw_version_ext; +static u32 bdf_version; +static u32 bdf_version_ext; #define CNSS_DUMP_FORMAT_VER 0x11 #define CNSS_DUMP_FORMAT_VER_V2 0x22 @@ -48,6 +53,47 @@ static struct cnss_plat_data *plat_env; static DECLARE_RWSEM(cnss_pm_sem); +int bdf_WifiChain_mode; +EXPORT_SYMBOL(bdf_WifiChain_mode); + +void cnss_set_bdf_name(u32 version, u32 ext) +{ + bdf_version = version; + bdf_version_ext = ext; +} +EXPORT_SYMBOL(cnss_set_bdf_name); + +static ssize_t bdf_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u.%u\n", + bdf_version, bdf_version_ext); +} +static DEVICE_ATTR_RO(bdf_name); + +int get_wifi_chain_mode(void) +{ + return bdf_WifiChain_mode; +} +EXPORT_SYMBOL(get_wifi_chain_mode); + +static ssize_t wifichain_flag_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, sizeof(buf), "%u\n", bdf_WifiChain_mode); +} +EXPORT_SYMBOL(wifichain_flag_show); + +static ssize_t wifichain_flag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + if (buf && size != 0) + bdf_WifiChain_mode = *buf; + return bdf_WifiChain_mode; +} +EXPORT_SYMBOL(wifichain_flag_store); + +static DEVICE_ATTR_RW(wifichain_flag); + static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = { "qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin", "utfbd30.bin", "epping30.bin", "evicted30.bin" @@ -2261,6 +2307,25 @@ cnss_use_nv_mac(struct cnss_plat_data *plat_priv) "use-nv-mac"); } +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) +{ + 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_RO(cnss_version_information); + static int cnss_probe(struct platform_device *plat_dev) { int ret = 0; @@ -2351,7 +2416,13 @@ static int cnss_probe(struct platform_device *plat_dev) ret = cnss_genl_init(); if (ret < 0) cnss_pr_err("CNSS genl init failed %d\n", ret); - + device_create_file(&plat_priv->plat_dev->dev, + &dev_attr_cnss_version_information); + push_component_info(WCN, "QCA6391", "QualComm"); + device_create_file(&plat_priv->plat_dev->dev, + &dev_attr_wifichain_flag); + device_create_file(&plat_priv->plat_dev->dev, + &dev_attr_bdf_name); cnss_pr_info("Platform driver probed successfully.\n"); return 0; @@ -2400,6 +2471,12 @@ static int cnss_remove(struct platform_device *plat_dev) cnss_put_resources(plat_priv); platform_set_drvdata(plat_dev, NULL); plat_env = NULL; + device_remove_file(&plat_priv->plat_dev->dev, + &dev_attr_cnss_version_information); + device_remove_file(&plat_priv->plat_dev->dev, + &dev_attr_wifichain_flag); + device_remove_file(&plat_priv->plat_dev->dev, + &dev_attr_bdf_name); return 0; } diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index a1992b1b0341..e40880c887aa 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -389,6 +389,9 @@ struct cnss_plat_data { u8 set_wlaon_pwr_ctrl; }; +int get_wifi_chain_mode(void); +void cnss_set_bdf_name(u32 version, u32 ext); + #ifdef CONFIG_ARCH_QCOM static inline u64 cnss_get_host_timestamp(struct cnss_plat_data *plat_priv) { diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index bdc3c5373add..e3b3d6e1bb1b 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "main.h" #include "bus.h" @@ -658,13 +659,13 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up) enum msm_pcie_pm_opt pm_ops; int retry = 0; - cnss_pr_vdbg("%s PCI link\n", link_up ? "Resuming" : "Suspending"); + //cnss_pr_vdbg("%s PCI link\n", link_up ? "Resuming" : "Suspending"); if (link_up) { pm_ops = MSM_PCIE_RESUME; } else { if (pci_priv->drv_connected_last) { - cnss_pr_vdbg("Use PCIe DRV suspend\n"); + //cnss_pr_vdbg("Use PCIe DRV suspend\n"); pm_ops = MSM_PCIE_DRV_SUSPEND; cnss_set_pci_link_status(pci_priv, PCI_GEN1); } else { @@ -3942,6 +3943,9 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic) plat_priv->ramdump_info_v2.dump_data_vaddr; struct image_info *fw_image, *rddm_image; struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; + struct cnss_subsys_info *subsys_info = + &plat_priv->subsys_info; + char sfr_buf[SFR_BUF_SIZE]; int ret, i, j; if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) @@ -3997,7 +4001,9 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic) dump_data->nentries += rddm_image->entries; - mhi_dump_sfr(pci_priv->mhi_ctrl); + mhi_dump_sfr(pci_priv->mhi_ctrl, sfr_buf, sizeof(sfr_buf)); + subsys_store_crash_reason(subsys_info->subsys_device, sfr_buf); + subsys_send_uevent_notify(&subsys_info->subsys_desc); cnss_pr_dbg("Collect remote heap dump segment\n"); diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 32eb9913982d..31c4eba67ac4 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "bus.h" #include "debug.h" @@ -20,6 +21,59 @@ #define REGDB_FILE_NAME "regdb.bin" #define DUMMY_BDF_FILE_NAME "bdwlan.dmy" +#define P821_PUBLIC_CHINA_DEFAULT_BDF "12wlan.b0c" +#define P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF "12wlan0.b0c" +#define P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF "12wlan1.b0c" +#define P821_PUBLIC_AMERICA_DEFAULT_BDF "12wlan.b0a" +#define P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF "12wlan0.b0a" +#define P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF "12wlan1.b0a" +#define P821_TMO_DEFAULT_BDF "12wlan.t0a" +#define P821_TMO_CHAIN0_ONLY_BDF "12wlan0.t0a" +#define P821_TMO_CHAIN1_ONLY_BDF "12wlan1.t0a" +#define P821_PUBLIC_EUROPE_DEFAULT_BDF "12wlan.b0e" +#define P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF "12wlan0.b0e" +#define P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF "12wlan1.b0e" +#define P821_PUBLIC_INDIA_DEFAULT_BDF "12wlan.b0i" +#define P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF "12wlan0.b0i" +#define P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF "12wlan1.b0i" +#define P821_PUBLIC_INDIA_SECOND_DEFAULT_BDF "12wlan.b1i" +#define P821_PUBLIC_INDIA_SECOND_CHAIN0_ONLY_BDF "12wlan0.b1i" +#define P821_PUBLIC_INDIA_SECOND_CHAIN1_ONLY_BDF "12wlan1.b1i" + +#define P805_PUBLIC_CHINA_DEFAULT_BDF "14wlan.b0c" +#define P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF "14wlan0.b0c" +#define P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF "14wlan1.b0c" +#define P805_PUBLIC_AMERICA_DEFAULT_BDF "14wlan.b0a" +#define P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF "14wlan0.b0a" +#define P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF "14wlan1.b0a" +#define P805_TMO_DEFAULT_BDF "14wlan.t0a" +#define P805_TMO_CHAIN0_ONLY_BDF "14wlan0.t0a" +#define P805_TMO_CHAIN1_ONLY_BDF "14wlan1.t0a" +#define P805_PUBLIC_EUROPE_DEFAULT_BDF "14wlan.b0e" +#define P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF "14wlan0.b0e" +#define P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF "14wlan1.b0e" +#define P805_PUBLIC_INDIA_DEFAULT_BDF "14wlan.b0i" +#define P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF "14wlan0.b0i" +#define P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF "14wlan1.b0i" +#define P805_PUBLIC_CHINA_SECOND_DEFAULT_BDF "14wlan.b1c" +#define P805_PUBLIC_CHINA_SECOND_CHAIN0_ONLY_BDF "14wlan0.b1c" +#define P805_PUBLIC_CHINA_SECOND_CHAIN1_ONLY_BDF "14wlan1.b1c" + +#define P811_PUBLIC_CHINA_DEFAULT_BDF "11wlan.b0c" +#define P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF "11wlan0.b0c" +#define P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF "11wlan1.b0c" +#define P811_PUBLIC_AMERICA_DEFAULT_BDF "11wlan.b0a" +#define P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF "11wlan0.b0a" +#define P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF "11wlan1.b0a" +#define P811_PUBLIC_INDIA_DEFAULT_BDF "11wlan.b0i" +#define P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF "11wlan0.b0i" +#define P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF "11wlan1.b0i" +#define P811_PUBLIC_EUROPE_DEFAULT_BDF "11wlan.b0e" +#define P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF "11wlan0.b0e" +#define P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF "11wlan1.b0e" +#define P867_VZW_DEFAULT_BDF "13wlan.v0a" +#define P867_VZW_CHAIN0_ONLY_BDF "13wlan0.v0a" +#define P867_VZW_CHAIN1_ONLY_BDF "13wlan1.v0a" #define QMI_WLFW_TIMEOUT_MS (plat_priv->ctrl_params.qmi_timeout) #define QMI_WLFW_TIMEOUT_JF msecs_to_jiffies(QMI_WLFW_TIMEOUT_MS) #define COEX_TIMEOUT QMI_WLFW_TIMEOUT_JF @@ -29,6 +83,7 @@ #define QMI_WLFW_MAC_READY_TIMEOUT_MS 50 #define QMI_WLFW_MAC_READY_MAX_RETRY 200 +static int tempstr; static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode) { @@ -469,17 +524,1008 @@ out: return ret; } +void cnss_get_india_sec_res_filename(char *filename, + u32 filename_len, + int hw_id, + int tempstr) +{ + if (hw_id == 54) + cnss_pr_dbg("it is INDIA EVT2 version, begin to load the Second INDIA BDF file"); + else if (hw_id == 55) + cnss_pr_dbg("it is INDIA DVT version, begin to load the Second INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_SECOND_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_SECOND_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_SECOND_DEFAULT_BDF); +} + +void cnss_get_china_sec_res_filename(char *filename, + u32 filename_len, + int hw_id, + int tempstr) +{ + if (hw_id == 51) + cnss_pr_dbg("it is CHINA EVT1 version, begin to load the Second CHINA BDF file"); + else if (hw_id == 52) + cnss_pr_dbg("it is CHINA DVT version, begin to load the Second CHINA BDF file"); + else if (hw_id == 53) + cnss_pr_dbg("it is CHINA PVT version, begin to load the Second CHINA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_SECOND_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_SECOND_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_SECOND_DEFAULT_BDF); +} + +void cnss_get_filename(char *filename, + u32 filename_len, + int pj_id, + int hw_id, + int rf_id, + int tempstr) +{ + if (pj_id == 12) { + if (hw_id == 11) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China T0 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO T0 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA T0 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe T0 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA T0 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 12) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China EVT1 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO EVT1 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA EVT1 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe EVT1 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA EVT1 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 13) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China EVT2 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO EVT2 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA EVT2 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe EVT2 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA EVT2 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 14) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China DVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO DVT version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA DVT version, begin to load the TMO INDIA file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe DVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA DVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 15) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China PVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO PVT version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA PVT version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe PVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA PVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P821_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 54 || hw_id == 55) { + cnss_get_india_sec_res_filename(filename, filename_len, + hw_id, tempstr); + } + } else if (pj_id == 14) { + if (hw_id == 11) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China T0 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO T0 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA T0 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe T0 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA T0 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 12) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China T1 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO T1 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA T1 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe T1 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA T1 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 13) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China EVT1 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO EVT1 version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA EVT1 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe EVT1 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA EVT1 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 14) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China DVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO DVT version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA DVT version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe DVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA DVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 15) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China PVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 12: + cnss_pr_dbg("it is TMO PVT version, begin to load the TMO BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_TMO_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_TMO_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_TMO_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA PVT version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe PVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA PVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P805_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 51 || hw_id == 52 || hw_id == 53) { + cnss_get_china_sec_res_filename(filename, filename_len, + hw_id, tempstr); + } else { + snprintf(filename, filename_len, + ELF_BDF_FILE_NAME); + } + } else if (pj_id == 11) { + if (hw_id == 11) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China T0 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA T0 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe T0 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA T0 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 12) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China EVT1 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA EVT1 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe EVT1 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA EVT1 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 13 || hw_id == 51) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China EVT2 version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA China EVT2 version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe China EVT2 version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA China EVT2 version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 14 || hw_id == 52) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China China DVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA DVT version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe DVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA DVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } else if (hw_id == 15 || hw_id == 53) { + switch (rf_id) { + case 11: + cnss_pr_dbg("it is China PVT version, begin to load the China BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_CHINA_DEFAULT_BDF); + break; + case 13: + cnss_pr_dbg("it is INDIA PVT version, begin to load the INDIA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_INDIA_DEFAULT_BDF); + break; + case 14: + cnss_pr_dbg("it is Europe PVT version, begin to load the Europe BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_EUROPE_DEFAULT_BDF); + break; + case 15: + cnss_pr_dbg("it is AMERICA PVT version, begin to load the AMERICA BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P811_PUBLIC_AMERICA_DEFAULT_BDF); + break; + } + } + } else if (pj_id == 13) { + if (hw_id == 11 || hw_id == 12 || + hw_id == 13 || hw_id == 14 || hw_id == 15) { + cnss_pr_dbg("it is vwz version, begin to load the VZW BDF file"); + if (tempstr == 1) + snprintf(filename, filename_len, + P867_VZW_CHAIN0_ONLY_BDF); + else if (tempstr == 2) + snprintf(filename, filename_len, + P867_VZW_CHAIN1_ONLY_BDF); + else + snprintf(filename, filename_len, + P867_VZW_DEFAULT_BDF); + } + } else { + snprintf(filename, filename_len, + ELF_BDF_FILE_NAME); + } +} + static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv, u32 bdf_type, char *filename, u32 filename_len) { char filename_tmp[MAX_FIRMWARE_NAME_LEN]; int ret = 0; + int pj_id = 0; + int hw_id = 0; + int rf_id = 0; + int bdf_WifiChain_mode; + tempstr = 0; + bdf_WifiChain_mode = get_wifi_chain_mode(); + cnss_pr_dbg("Get the value of bdf_WifiChain_mode: %d", bdf_WifiChain_mode); + if (bdf_WifiChain_mode > 48) + tempstr = bdf_WifiChain_mode - 48; + pj_id = get_prj_version(); + hw_id = get_hw_board_version(); + rf_id = get_rf_version(); + cnss_pr_dbg("cnss get_prj_version(): %d", pj_id); + cnss_pr_dbg("cnss get_hw_board_version(): %d", hw_id); + cnss_pr_dbg("cnss get_rf_version(): %d", rf_id); switch (bdf_type) { case CNSS_BDF_ELF: - if (plat_priv->board_info.board_id == 0xFF) - snprintf(filename_tmp, filename_len, ELF_BDF_FILE_NAME); + /* WIFI MODIFICATION: */ + //if (plat_priv->board_info.board_id == 0xFF) + // snprintf(filename_tmp, filename_len, ELF_BDF_FILE_NAME); + if (plat_priv->board_info.board_id == 0xFF) { + cnss_get_filename(filename, filename_len, pj_id, + hw_id, rf_id, tempstr); + return ret; + } + /* WIFI MODIFICATION: */ else if (plat_priv->board_info.board_id < 0xFF) snprintf(filename_tmp, filename_len, ELF_BDF_FILE_NAME_PREFIX "%02x", @@ -535,6 +1581,10 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, const u8 *temp; unsigned int remaining; int ret = 0; + char get_bdf_name[3] = {0}; + char get_bdf_name_ext[4] = {0}; + u32 bdf_name; + u32 bdf_name_ext; cnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n", plat_priv->driver_state, bdf_type); @@ -631,6 +1681,15 @@ bypass_bdf: req->seg_id++; } + strlcpy(get_bdf_name, filename, sizeof(get_bdf_name)); + bdf_name = cnss_atoi(get_bdf_name); + if (tempstr == 0) + strlcpy(get_bdf_name_ext, filename + 7, 4); + else + strlcpy(get_bdf_name_ext, filename + 8, 4); + bdf_name_ext = cnss_atoi(get_bdf_name_ext); + cnss_set_bdf_name(bdf_name, bdf_name_ext); + if (bdf_type != CNSS_BDF_DUMMY) release_firmware(fw_entry); @@ -649,6 +1708,36 @@ err_req_fw: return ret; } +int cnss_pow_ten(int n) +{ + int result = 1; + int i; + + for (i = 1; i <= n; i++) + result = result * 10; + return result; +} + +int cnss_atoi(const char *numbers) +{ + int length = strlen(numbers); + int sum = 0; + int i = 0; + + if (length == 3) { + sum = (numbers[0] - 'a' + 10) * cnss_pow_ten(3) + (numbers[1] - '0') * cnss_pow_ten(2) + + numbers[2] - 'a' + 10; + } else { + for (i = 0; i < length; i++) { + if (numbers[i] >= '0' && numbers[i] <= '9') + sum = sum + (numbers[i] - '0') * cnss_pow_ten(length - i - 1); + } + if (tempstr != 0) + sum = sum * 10 + tempstr - 1; + } + return sum; +} + int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv) { struct wlfw_m3_info_req_msg_v01 *req; diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h index 90a9dbddcbed..5c01026768a7 100644 --- a/drivers/net/wireless/cnss2/qmi.h +++ b/drivers/net/wireless/cnss2/qmi.h @@ -33,6 +33,8 @@ struct cnss_qmi_event_qdss_trace_save_data { #include "coexistence_service_v01.h" #include "ip_multimedia_subsystem_private_service_v01.h" +int cnss_pow_ten(int n); +int cnss_atoi(const char *numbers); int cnss_qmi_init(struct cnss_plat_data *plat_priv); void cnss_qmi_deinit(struct cnss_plat_data *plat_priv); unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv); diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index ab47b32f9335..7ae74f743794 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -22,6 +22,8 @@ #include #endif #include +#include +#include #include struct nqx_platform_data { @@ -1454,6 +1456,13 @@ static int nqx_probe(struct i2c_client *client, platform_data->en_gpio); goto err_en_gpio; } + if (get_boot_mode() == MSM_BOOT_MODE_FACTORY) { + gpio_set_value(platform_data->en_gpio, 0); + dev_err(&client->dev, + "%s: ftm_at mode, set ven low and dont probe pn5xx\n", + __func__); + goto err_en_gpio; + } } else { dev_err(&client->dev, "%s: nfc reset gpio not provided\n", __func__); @@ -1628,6 +1637,8 @@ static int nqx_probe(struct i2c_client *client, gpio_set_value(platform_data->en_gpio, 0); /* We don't think there is hardware switch NFC OFF */ goto err_request_hw_check_failed; + } else { + push_component_info(NFC, "SN100", "NXP"); } /* Register reboot notifier here */ diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 688f1226eea2..6ac9f7d050d5 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -32,6 +32,8 @@ #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 +675,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 100755 index 000000000000..3dc7c64c4d58 --- /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 000000000000..fdbbc4388ac4 --- /dev/null +++ b/drivers/oneplus/Makefile @@ -0,0 +1,19 @@ +# 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 += vibrator/ +obj-y += power/ +obj-y += vibrator/ +#obj-y += power/ +obj-y += oneplus_healthinfo/ +obj-y += mm/ +obj-y += opslalib/ +obj-y += vl53L1/ +obj-y += op_freezer/ +obj-y += hung_task_enhance/ diff --git a/drivers/oneplus/coretech/Kconfig b/drivers/oneplus/coretech/Kconfig new file mode 100755 index 000000000000..82a7b801684c --- /dev/null +++ b/drivers/oneplus/coretech/Kconfig @@ -0,0 +1,64 @@ +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 TPD + default n + bool "a task placement decision for cpu limitation" diff --git a/drivers/oneplus/coretech/Makefile b/drivers/oneplus/coretech/Makefile new file mode 100755 index 000000000000..d677b5398c5a --- /dev/null +++ b/drivers/oneplus/coretech/Makefile @@ -0,0 +1,32 @@ +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/ diff --git a/drivers/oneplus/coretech/adj_chain/Makefile b/drivers/oneplus/coretech/adj_chain/Makefile new file mode 100755 index 000000000000..8360bc80ce00 --- /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 100755 index 000000000000..261130fcac21 --- /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 100755 index 000000000000..cb855c5643d4 --- /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 100755 index 000000000000..9bb76201d904 --- /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 100755 index 000000000000..1e856b814c61 --- /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 100755 index 000000000000..500f5fb9905e --- /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 100755 index 000000000000..b39d0d10b420 --- /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 100755 index 000000000000..46ffffbd0da1 --- /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 100755 index 000000000000..95cf3058089a --- /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 100755 index 000000000000..85e3a086544b --- /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 100755 index 000000000000..7c78c2251d68 --- /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 100755 index 000000000000..3bbeb78aed50 --- /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 100755 index 000000000000..a1e70c67e401 --- /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 100755 index 000000000000..3cef022e6559 --- /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 100755 index 000000000000..05b13b91adec --- /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 100755 index 000000000000..622fcb9d191c --- /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 100755 index 000000000000..86c8f1b1699e --- /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 100755 index 000000000000..e857d402bb82 --- /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 100755 index 000000000000..9680b5ce93d6 --- /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 100755 index 000000000000..6538bfdbea34 --- /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 100755 index 000000000000..418f3edafa58 --- /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 100755 index 000000000000..e82ea2deb51d --- /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 100755 index 000000000000..91e2835a8ebd --- /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 100755 index 000000000000..b127799cb3f7 --- /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 000000000000..0277b94748b6 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 000000000000..239bcdc57baf 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 100755 index 000000000000..32fd307dc39c --- /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 100755 index 000000000000..6235862bf602 --- /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 100755 index 000000000000..bfb3cce849c9 --- /dev/null +++ b/drivers/oneplus/coretech/houston/houston.c @@ -0,0 +1,2448 @@ +#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", + //"modem-ambient-usr", "skin-msm-therm-usr", + "skin-therm-usr", "msm-therm", + "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", "appSwapTime", "appSwapDuration", + "appEnqueueDuration", "sfTotalDuration", "sfPresentTime", + "Vsync", "missedLayer", "render_pid", "render_util", + "nt_rtg", "rtg_util_sum" +}; + +/* + * 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 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); + +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, +}; + +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; +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"; + } + return "NONE"; +} + +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_1)) + 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); + +/* 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); + +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) { + case 0: case 1: case 2: case 3: hus = &ht_utils[0]; break; + case 4: case 5: case 6: hus = &ht_utils[1]; break; + case 7: hus = &ht_utils[2]; break; + default: + /* should not happen */ + ht_logw("wrnog first cpu utils idx %d\n", first_cpu); + return; + } + + if (cpu == CLUS_2_IDX) + 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_1) + return; + if (ht_tzd_idx <= HT_THERM_1) { + ++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; + char fps_layer_name[FPS_DATA_BUF_SIZE] = {0}; + char process_name[FPS_DATA_BUF_SIZE] = {0}; + static int cur_idx = 0; + //size_t len; + int i = 0, ret; + + if (strlen(buf) >= FPS_DATA_BUF_SIZE) + return 0; + + memset(fps_layer_name, 0, FPS_DATA_BUF_SIZE); + + ret = sscanf(buf, "%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%lld,%s %s\n", + &fps_data[0], &fps_data[1], &fps_data[2], &fps_data[3], + &fps_data[4], &fps_data[5], &fps_data[6], &fps_data[7], + &fps_data[8], &fps_align, + process_name, fps_layer_name); + + if (ret != 12) { + /* 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; + } + + ht_logv("fps data params: %llu %llu %llu %llu %llu %llu %llu %llu %llu %lld %s %s\n", + fps_data[0], fps_data[1], fps_data[2], fps_data[3], fps_data[4], + fps_data[5], fps_data[6], fps_data[7], fps_data[8], fps_align, + process_name, fps_layer_name); + + /* + * cached_fps should be always updated + * rounding up + */ + atomic_set(&cached_fps[0], (fps_data[0] + 5)/ 10); + 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]; //appSwapTime + monitor.buf->data[cur_idx][HT_FPS_4] = fps_data[3]; //appSwapDuration + monitor.buf->data[cur_idx][HT_FPS_5] = fps_data[4]; //appEnqueueDuration + monitor.buf->data[cur_idx][HT_FPS_6] = fps_data[5]; //sfTotalDuration + monitor.buf->data[cur_idx][HT_FPS_7] = fps_data[6]; //sfPresentTime + monitor.buf->data[cur_idx][HT_FPS_8] = fps_data[7]; //vSync + monitor.buf->data[cur_idx][HT_FPS_PID] = fps_data[8]; //pid + monitor.buf->data[cur_idx][HT_FPS_ALIGN]= fps_align; //fps align ts + + fps_layer_name[FPS_LAYER_LEN - 1] = '\0'; + process_name[FPS_PROCESS_NAME_LEN - 1] = '\0'; + + i = 0; + while (fps_layer_name[i]) { + monitor.buf->layer[cur_idx][i] = fps_layer_name[i]; + ++i; + } + + i = 0; + while (process_name[i]) { + monitor.buf->process[cur_idx][i] = process_name[i]; + ++i; + } + 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; + 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; + 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: + ht_cpuload_helper(0, 4, &cli); + break; + case 1: + ht_cpuload_helper(1, 3, &cli); + 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; + } + } + 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); + + /* 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; + 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; + 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_1; ++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_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_1)? 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 100755 index 000000000000..c42f0edae6c0 --- /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 100755 index 000000000000..215669188fd9 --- /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 100755 index 000000000000..d9da29dc305a --- /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 100755 index 000000000000..0e017db3bf18 --- /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 100755 index 000000000000..1f6206b46eaa --- /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 100755 index 000000000000..c7f619b8b4d6 --- /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 100755 index 000000000000..dd48d0e4874c --- /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 100755 index 000000000000..fd17e80e9e4d --- /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 100755 index 000000000000..93063d60cd9b --- /dev/null +++ b/drivers/oneplus/coretech/im/im.c @@ -0,0 +1,399 @@ +#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 "}, + {"", "hwui "}, + {"", "render "}, + {"neplus.launcher", "launcher "}, +}; + +/* 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; + } + } + + /* 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; + } + } +} + +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) +{ + task->im_flag |= flag; +} + +void im_set_flag_current(int flag) +{ + current->im_flag |= flag; +} + +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); +} diff --git a/drivers/oneplus/coretech/memplus/Makefile b/drivers/oneplus/coretech/memplus/Makefile new file mode 100755 index 000000000000..2bff8d58cde3 --- /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 100755 index 000000000000..cad044c7e1e3 --- /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 100755 index 000000000000..69e8baedf247 --- /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 100755 index 000000000000..72b9bec7e2f8 --- /dev/null +++ b/drivers/oneplus/coretech/memplus/core/memplus_core.c @@ -0,0 +1,1674 @@ +#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 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; + + //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; + /* 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: 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 100755 index 000000000000..799fad416617 --- /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 100755 index 000000000000..2021a25b086a --- /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 100755 index 000000000000..3dc134c9eb10 --- /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/smartboost/Makefile b/drivers/oneplus/coretech/smartboost/Makefile new file mode 100755 index 000000000000..6091ef65fe33 --- /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 100755 index 000000000000..a36d13e65523 --- /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 100755 index 000000000000..cf2604c0f0a9 --- /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 100755 index 000000000000..6d5019c223c1 --- /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 100755 index 000000000000..804712c82f34 --- /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 100755 index 000000000000..3526ff456811 --- /dev/null +++ b/drivers/oneplus/coretech/tpd/tpd.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include + +/* + * Task Placement Decision + */ + +static int tpd_log_lv = 2; +module_param_named(log_lv, tpd_log_lv, int, 0664); + +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; + + 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 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_logi("%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 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 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_logi("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 tp_decision = -1; + int ret; + + ret = sscanf(buf, "%u,%u,%d\n", + &pid, &tid, &tp_decision); + + tpd_logi("tpd param pid:%u tid:%u, decision:%d from %s %d\n", + pid, tid, tp_decision, current->comm, current->pid); + + if (ret != 3) { + tpd_loge("Invalid params!!!!!!"); + return 0; + } + + tag_from_tid(pid, tid, tp_decision); + + return 0; +} + +static struct kernel_param_ops tpd_ops = { + .set = tpd_store, +}; +module_param_cb(tpd_id, &tpd_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)) + 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\n", tsk->pid, tsk->comm, + tsk->tpd, suggest_cpu, task_is_fg(tsk)); + 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)) { + tpd_loge("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; + } +} + +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)) { + 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; +} diff --git a/drivers/oneplus/coretech/uxchain/Makefile b/drivers/oneplus/coretech/uxchain/Makefile new file mode 100755 index 000000000000..c906a8fde143 --- /dev/null +++ b/drivers/oneplus/coretech/uxchain/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_UXCHAIN) += uxchain.o diff --git a/drivers/oneplus/coretech/uxchain/uxchain.c b/drivers/oneplus/coretech/uxchain/uxchain.c new file mode 100755 index 000000000000..37e4a78712da --- /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/uxcore/Makefile b/drivers/oneplus/coretech/uxcore/Makefile new file mode 100755 index 000000000000..6a11f257f930 --- /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 000000000000..999d1cab9e93 --- /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 000000000000..daa046bcd0fa --- /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 100755 index 000000000000..683311cabebe --- /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 000000000000..11c77b644c81 --- /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 100755 index 000000000000..c840effd92c1 --- /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 000000000000..b9c310127661 --- /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 000000000000..6b4eb6a88f94 --- /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 000000000000..feff6f495cf3 --- /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 100755 index 000000000000..8a49d7a53097 --- /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 100755 index 000000000000..c4961e520700 --- /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 100755 index 000000000000..9cf0bbfdfd11 --- /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/framework/Kconfig b/drivers/oneplus/framework/Kconfig new file mode 100755 index 000000000000..a6ceadc5b308 --- /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 100755 index 000000000000..fecf0231a4ba --- /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 100755 index 000000000000..bdfeba3a7943 --- /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 100755 index 000000000000..a965bd7e9ba7 --- /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 100755 index 000000000000..3f09d519dd48 --- /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 100755 index 000000000000..3b12d46b5c4b --- /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 100755 index 000000000000..d137c290f4eb --- /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 000000000000..5b79a3660fac --- /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 000000000000..ed9f07c14f09 --- /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 100755 index 000000000000..7e691d1ce02e --- /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 100755 index 000000000000..245b48d06700 --- /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 100755 index 000000000000..7777908be121 --- /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 100755 index 000000000000..f6698f7ec4be --- /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 100755 index 000000000000..73f993609e63 --- /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 100755 index 000000000000..58dcab122070 --- /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 100755 index 000000000000..85f6919fd650 --- /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 100755 index 000000000000..937ca1b1d833 --- /dev/null +++ b/drivers/oneplus/hung_task_enhance/hung_task_enhance.c @@ -0,0 +1,184 @@ +/*************************************************************** +** 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; + 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 100755 index 000000000000..885f26b2229e --- /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 100755 index 000000000000..2aa22a2e119e --- /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 100755 index 000000000000..1a0f2ba4b74c --- /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 100755 index 000000000000..b3ed5d70989b --- /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 100755 index 000000000000..05001be78aa0 --- /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 100755 index 000000000000..fe8ecf5d2cfe --- /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 100755 index 000000000000..9b0ef15127b0 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/houston.h @@ -0,0 +1,208 @@ +#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 +#define HT_CPUS_PER_CLUS 4 +#define CLUS_0_IDX 0 +#define CLUS_1_IDX 4 +#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 (9) +#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_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 +}; + +/* 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_MAX 2 + +#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 100755 index 000000000000..42e10f499b60 --- /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 100755 index 000000000000..48e9932325cb --- /dev/null +++ b/drivers/oneplus/include/linux/oem/im.h @@ -0,0 +1,195 @@ +#ifndef __IM_H__ +#define __IM_H__ + +#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_LAUNCHER, // launcher + 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_LAUNCHER (1 << IM_ID_LAUNCHER) + +/* 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) +{ + return task->im_flag & + (IM_MAIN | + IM_ENQUEUE | + IM_SURFACEFLINGER | + IM_GL | + IM_VK | + IM_HWC | + IM_RENDER); +} + +static inline bool im_graphic(struct task_struct *task) +{ + return task->im_flag & (IM_GL | IM_VK | IM_HWUI); +} + +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_launcher(struct task_struct *task) +{ + return task->im_flag & IM_LAUNCHER; +} + +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); +#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_launcher(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) {} +#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 100755 index 000000000000..e4a8632bfa25 --- /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 100755 index 000000000000..47ec6943e23a --- /dev/null +++ b/drivers/oneplus/include/linux/oem/oem_force_dump.h @@ -0,0 +1,53 @@ +/* + * 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 +int open_selinux_switch(void); +int set_oem_selinux_state(int state); +int get_oem_selinux_state(void); + +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 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; +} + +#endif diff --git a/drivers/oneplus/include/linux/oem/oneplus_healthinfo.h b/drivers/oneplus/include/linux/oem/oneplus_healthinfo.h new file mode 100755 index 000000000000..1ea9c51f35d0 --- /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 100755 index 000000000000..c3162c446122 --- /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 100755 index 000000000000..9a43dded248c --- /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 100755 index 000000000000..27e359c838b6 --- /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 100755 index 000000000000..cb3978255fca --- /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 100755 index 000000000000..ab3b677a4e4b --- /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 100755 index 000000000000..5fe0ee83c6b4 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/power/oem_external_fg.h @@ -0,0 +1,142 @@ +#ifndef __OEM_EXTERNAL_FG_H__ +#define __OEM_EXTERNAL_FG_H__ +#include +#include + +enum { + ADAPTER_FW_UPDATE_NONE, + ADAPTER_FW_NEED_UPDATE, + ADAPTER_FW_UPDATE_SUCCESS, + ADAPTER_FW_UPDATE_FAIL, +}; + +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_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); + int (*get_batt_fcc)(void); + 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); +}; + +struct notify_dash_event { + int (*notify_event)(void); + int (*op_contrl)(int status, bool check_power_ok); + int (*notify_dash_charger_present)(int true); +}; + +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_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_REMOVED, /* on v2.2 only */ + BATT_STATUS_INVALID_v1 = BATT_STATUS_REMOVED, + BATT_STATUS_INVALID +}; +void op_pm8998_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_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_medium(void); +bool check_call_on_status(void); +void update_fast_switch_off_status(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 100755 index 000000000000..b9a5ba0048b1 --- /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 100755 index 000000000000..6901279a66f6 --- /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 100755 index 000000000000..541524d5f87a --- /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/tpd.h b/drivers/oneplus/include/linux/oem/tpd.h new file mode 100755 index 000000000000..97536a700ee8 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/tpd.h @@ -0,0 +1,63 @@ +#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 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) + +#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); +static inline bool is_tpd_task(struct task_struct *tsk) { return tsk ? (tsk->tpd != 0) : false; } +#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_tpd_task(struct task_struct *tsk) { return false; } +#endif + +#endif diff --git a/drivers/oneplus/input/Kconfig b/drivers/oneplus/input/Kconfig new file mode 100755 index 000000000000..2544c97939e7 --- /dev/null +++ b/drivers/oneplus/input/Kconfig @@ -0,0 +1,3 @@ +# oem device deriver +source "drivers/oneplus/input/touchscreen/Kconfig" +source "drivers/oneplus/input/fingerprint/Kconfig" diff --git a/drivers/oneplus/input/Makefile b/drivers/oneplus/input/Makefile new file mode 100755 index 000000000000..53446025f24c --- /dev/null +++ b/drivers/oneplus/input/Makefile @@ -0,0 +1,6 @@ +# oem device deriver +# +obj-y += touchscreen/ +obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/ + + diff --git a/drivers/oneplus/input/fingerprint/Kconfig b/drivers/oneplus/input/fingerprint/Kconfig new file mode 100755 index 000000000000..9a505aa689b4 --- /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 100755 index 000000000000..3b6ebd1ac501 --- /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 100755 index 000000000000..c9846540e94f --- /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 000000000000..396a7b09d877 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.c @@ -0,0 +1,213 @@ + +#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; + } +*/ + + 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 000000000000..7ff5f8ecb395 --- /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 100755 index 000000000000..9faa4a643604 --- /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 000000000000..59e2bf624304 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/gf_spi.c @@ -0,0 +1,1157 @@ +/* + * 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 (1) { + status = gf_pinctrl_init(gf_dev); + if (status) + goto err_irq; + } + if (get_boot_mode() != MSM_BOOT_MODE_FACTORY) { + if (1) { + 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 (1) { + 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 000000000000..ca1a8719df3a --- /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 100755 index 000000000000..ce5b3babeb52 --- /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 000000000000..2273d740d713 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/platform.c @@ -0,0 +1,193 @@ +/* + * 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; + 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; + + 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 100755 index 000000000000..d5ccc1e7e91d --- /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 100755 index 000000000000..b1153ac2bac2 --- /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/Kconfig b/drivers/oneplus/input/touchscreen/Kconfig new file mode 100755 index 000000000000..6858fe077ed5 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Kconfig @@ -0,0 +1,4 @@ + +source "drivers/oneplus/input/touchscreen/util_interface/Kconfig" +source "drivers/oneplus/input/touchscreen/samsung/Kconfig" +source "drivers/oneplus/input/touchscreen/synaptics/Kconfig" diff --git a/drivers/oneplus/input/touchscreen/Makefile b/drivers/oneplus/input/touchscreen/Makefile new file mode 100755 index 000000000000..f9f565e28b89 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the touchscreen drivers. +# +obj-y += samsung/ +obj-y += util_interface/ +obj-y += touchpanel_common_driver.o +obj-y += synaptics/ diff --git a/drivers/oneplus/input/touchscreen/samsung/Kconfig b/drivers/oneplus/input/touchscreen/samsung/Kconfig new file mode 100755 index 000000000000..07a229da9ff0 --- /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 000000000000..1c1e53b8f57c --- /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 100755 index 000000000000..e243fd535064 --- /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 000000000000..5cfbd7f37bce --- /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 000000000000..3a5df3c1de54 --- /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 000000000000..7fa3f3d9758b --- /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 000000000000..854660db2d47 --- /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 000000000000..c5de01931112 --- /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 000000000000..da9e62b32c32 --- /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 000000000000..c9411cef2832 --- /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 000000000000..499862eb1804 --- /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 000000000000..72d0a6c4ae5c --- /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 000000000000..410252b441bc --- /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 000000000000..541b4582e355 --- /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 000000000000..855633721db8 --- /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 000000000000..2c00b01e80af --- /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 000000000000..866f23cae3fb --- /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 000000000000..45f0c9d643a9 --- /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 000000000000..d4c210de81eb --- /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 000000000000..2f93b27947ff --- /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 000000000000..33c89845da74 --- /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 000000000000..9d245b69ef2c --- /dev/null +++ b/drivers/oneplus/input/touchscreen/touchpanel_common.h @@ -0,0 +1,656 @@ +/*********************************************************** + * 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 +#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 { + 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, + 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 fp_underscreen_info { + uint8_t touch_state; + uint8_t area_rate; + uint16_t x; + uint16_t y; +}; + + +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 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; +}; + +/* 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 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 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 report_flow_unlock_support; /*report flow is unlock, need to lock when all touch release*/ +#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 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 (*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 000000000000..1db32d0c57a6 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/touchpanel_common_driver.c @@ -0,0 +1,5754 @@ +#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; +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 *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 (!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->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 { + 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 { + 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 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 { + tp_datalogger_handle(ts); + } + } + if (CHK_BIT(cur_event, IRQ_FACE_STATE) && ts->fd_enable) { + tp_face_detect_handle(ts); + } + 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 { + 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; + + 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_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 + 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"); + } + + // 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; + } + + //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 { + 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; + ret = register_reverse_charge_notifier(&ts->reverse_charge_notif); + if (ret) + TPD_INFO("unable to register severse_charge_notifier:%d\n", ret); + + ts->tp_delta_print_notif.notifier_call = tp_delta_print_notifier_callback; + ret = register_tp_delta_print_notifier(&ts->tp_delta_print_notif); + if (ret) + TPD_INFO("unable to register tp_delta_print_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); + 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->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) { + 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) { //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) { + 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) { + 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 000000000000..b618978aff94 --- /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 000000000000..ce1219f11d20 --- /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 000000000000..19be4449b129 --- /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 000000000000..c6bbb60272ee --- /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 000000000000..0e00c08923fb --- /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/kernel/Kconfig b/drivers/oneplus/kernel/Kconfig new file mode 100755 index 000000000000..0f5ed7b0db82 --- /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 100755 index 000000000000..ad4ad63dc990 --- /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 100755 index 000000000000..362b52b0025f --- /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 100755 index 000000000000..0f4e6fec54bb --- /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 100755 index 000000000000..0d839b560c1c --- /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 100755 index 000000000000..ba5c98f27a13 --- /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 100755 index 000000000000..a725b95be99e --- /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 100755 index 000000000000..a859bfc15c66 --- /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 100755 index 000000000000..abdcf5c4f6e9 --- /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 100755 index 000000000000..6b3be597e2e3 --- /dev/null +++ b/drivers/oneplus/misc/bootloader_log.c @@ -0,0 +1,228 @@ +/* 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) +{ + 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"); + diff --git a/drivers/oneplus/misc/device_info.c b/drivers/oneplus/misc/device_info.c new file mode 100755 index 000000000000..fa70ebd1cb06 --- /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 100755 index 000000000000..cf83295745ff --- /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 100755 index 000000000000..9649dbf1f1d6 --- /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 100755 index 000000000000..9be2bd3019ef --- /dev/null +++ b/drivers/oneplus/misc/oem_force_dump.c @@ -0,0 +1,290 @@ +/* + * 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 + +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; +static int selinux_switch; +enum key_stat_item pwr_status, vol_up_status; + +void send_sig_to_get_trace(char *name) +{ + struct task_struct *g, *t; + + for_each_process_thread(g, t) { + if (!strncmp(t->comm, name, TASK_COMM_LEN)) { + do_send_sig_info(SIGQUIT, SEND_SIG_FORCED, t, PIDTYPE_TGID); + msleep(500); + return; + } + } +} + +void send_sig_to_get_tombstone(char *name) +{ + struct task_struct *p; + + 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; + } + } +} + +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); + +} +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) { + set_oem_selinux_state(1); + message_state = 1; + queue_work(smg_workwq, &smg_work); + state = NONE; + } else if (code == KEY_VOLUMEDOWN && !value) { + message_state = 2; + queue_work(smg_workwq, &smg_work); + state = NONE; + } else + state = NONE; + break; + } +} +int set_oem_selinux_state(int state) +{ + selinux_switch = state; + return 0; +} +int get_oem_selinux_state(void) +{ + return selinux_switch; +} + +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 100755 index 000000000000..3f329fac4801 --- /dev/null +++ b/drivers/oneplus/misc/op_rf_cable_monitor.c @@ -0,0 +1,619 @@ +/*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; +#define CABLE_GPIO_NUM 4 +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 100755 index 000000000000..2620a7dd0cf2 --- /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 100755 index 000000000000..e1d865476506 --- /dev/null +++ b/drivers/oneplus/misc/project_info.c @@ -0,0 +1,888 @@ +/* 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 "}, + {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 100755 index 000000000000..451bb87cf2c2 --- /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 100755 index 000000000000..ed77c730499e --- /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 100755 index 000000000000..63734d216ef1 --- /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 100755 index 000000000000..d0f0db7a32dd --- /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 100755 index 000000000000..f84322fabfc3 --- /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 100755 index 000000000000..4d2458ce80dd --- /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 100755 index 000000000000..5bb5a9d5d4fc --- /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 100755 index 000000000000..aae73f8bd5bd --- /dev/null +++ b/drivers/oneplus/oneplus_healthinfo/Kconfig @@ -0,0 +1,11 @@ +config ONEPLUS_HEALTHINFO + 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 100755 index 000000000000..9f5e4add6da9 --- /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 100755 index 000000000000..1e438982dd34 --- /dev/null +++ b/drivers/oneplus/oneplus_healthinfo/oneplus_healthinfo.c @@ -0,0 +1,1742 @@ +/********************************************************************************** +* 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 struct delayed_work ohm_detect_ws; +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; + +void ohm_action_trig(int type) +{ + 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; + } + sprintf(ohm_detect_env[1], "OHMTYPE=%s", sched_list[type]); + sprintf(ohm_detect_env[2], "NOLEVEL"); + ohm_detect_env[MAX_OHMEVENT_PARAM - 1] = NULL; + cancel_delayed_work(&ohm_detect_ws); + schedule_delayed_work(&ohm_detect_ws, msecs_to_jiffies(1)); + } +} + +void ohm_action_trig_level(int type, bool highlevel) +{ + 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; + 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; + cancel_delayed_work(&ohm_detect_ws); + schedule_delayed_work(&ohm_detect_ws, msecs_to_jiffies(1)); + last_trig = jiffies; + } +} + +void ohm_detect_work(struct work_struct *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"); +} + +void ohm_action_init(void) +{ + int i = 0; + 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; + INIT_DELAYED_WORK(&ohm_detect_ws, ohm_detect_work); + 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 000000000000..295f22419562 --- /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 y + 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 100755 index 000000000000..488674528145 --- /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 100755 index 000000000000..4d147487ad47 --- /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 100755 index 000000000000..3bdde1198324 --- /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 100755 index 000000000000..f00ba65c4f7d --- /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 100755 index 000000000000..6794aaf7c5fb --- /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 100755 index 000000000000..91e43b78c341 --- /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 100755 index 000000000000..e61ca251444e --- /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 100755 index 000000000000..cc45babc31d0 --- /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 000000000000..b24a4dbf7dfa --- /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 100755 index 000000000000..95da8d7ec12c --- /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 100755 index 000000000000..37f4fa19058e --- /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 100755 index 000000000000..4bb970393479 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/Kconfig @@ -0,0 +1,29 @@ +# 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 + diff --git a/drivers/oneplus/power/supply/qcom/Makefile b/drivers/oneplus/power/supply/qcom/Makefile new file mode 100755 index 000000000000..c301159113c4 --- /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 op_dash_adapter.o +obj-y += bq27541_fuelgauger.o +obj-y += oneplus_fastchg.o + diff --git a/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c new file mode 100755 index 000000000000..08514f71d7d5 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c @@ -0,0 +1,2201 @@ +/* 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 + +/* david.liu@bsp, 20161004 Add BQ27411 support */ +#define CONFIG_GAUGE_BQ27411 1 +#define DEVICE_TYPE_BQ27541 0x0541 +#define DEVICE_TYPE_BQ27411 0x0421 +#define DEVICE_BQ27541 0 +#define DEVICE_BQ27411 1 + +#define DRIVER_VERSION "1.1.0" +/* 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 0x0c +#define BQ27411_REG_AI 0x10 +#define BQ27411_REG_SOC 0x1c +#define BQ27411_REG_HEALTH 0x20 +#define BQ27411_REG_FCC 0xE + +#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 + +#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) +/* 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); + +struct bq27541_device_info; +struct bq27541_access_methods { + int (*read)(u8 reg, int *rt_value, int b_single, + struct bq27541_device_info *di); +}; + +#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; +}; +#endif + +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; + + 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; + unsigned long soc_store_time; +#ifdef CONFIG_GAUGE_BQ27411 + int device_type; + struct cmd_address cmd_addr; + bool modify_soc_smooth; + bool already_modify_smooth; +#endif + bool bat_4p45v; + bool check_match; +}; + +#include +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 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. + */ +static int bq27541_battery_temperature(struct bq27541_device_info *di) +{ + int ret; + int temp = 0; + int error_temp; + static int count; + + /* 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; + } + 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); + return ret; + } + } else { + return di->batt_vol_pre; + } + di->batt_vol_pre = volt * 1000; + return volt * 1000; +} + +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; +} + +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 3250000 +#define CAPACITY_CALIBRATE_TIME_60_PERCENT 45 /* 45s */ +#define LOW_BATTERY_CAPACITY_THRESHOLD 20 + +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) && + (di->soc_pre > 60)) { + 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 < 20) + || (!bq27541_di->fastchg_started + && time_last < 30)) + 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 { + 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(BQ27411_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; + + bq27541_di->disable_calib_soc = true; + soc = bq27541_battery_soc(bq27541_di, 0); + bq27541_di->disable_calib_soc = 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) { + 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; + } + } + 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_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, +}; +#define BATTERY_SOC_UPDATE_MS 12000 +#define LOW_BAT_SOC_UPDATE_MS 6000 + +#define RESUME_SCHDULE_SOC_UPDATE_WORK_MS 60000 + +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; + + 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); + 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); + 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)); +} + +static bool bq27541_registered; +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) { + 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; + } 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; + } +} +#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; + 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); + exfg_information_register(&bq27541_batt_gauge); + 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); + 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; +} + +#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); +} +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 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); + 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->rtc_resume_time - di->lcd_off_time >= TWO_POINT_FIVE_MINUTES) { + 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)); + } + 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/oneplus_fastchg.c b/drivers/oneplus/power/supply/qcom/oneplus_fastchg.c new file mode 100755 index 000000000000..668f18ead63c --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/oneplus_fastchg.c @@ -0,0 +1,1840 @@ +/**************************************************** + **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 +#include "linux/oem/project_info.h" + + +#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 + +struct fastchg_device_info { + struct i2c_client *client; + struct miscdevice dash_device; + struct mutex read_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_state_active; + struct pinctrl_state *pinctrl_mcu_data_state_suspended; + 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; + bool is_4300mAh_4p45_support; + bool is_4320mAh_4p45_support; + bool is_4510mAh_4p45_support; + bool is_skin_temp_high; + bool is_skin_thermal_medium; + bool is_call_on; + 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 ap_clk; + int ap_data; + int dash_enhance; + int dashchg_fw_ver_count; + + 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; + char fw_id[255]; + char manu_name[255]; +}; + +struct fastchg_device_info *fastchg_di; + +static unsigned char *dashchg_firmware_data; +static struct i2c_client *mcu_client; + +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"); + } +} + +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_data_active(struct fastchg_device_info *chip) +{ + gpio_direction_input(chip->ap_data); + if (chip->pinctrl && + !IS_ERR_OR_NULL(chip->pinctrl_mcu_data_state_active)) + pinctrl_select_state(chip->pinctrl, + chip->pinctrl_mcu_data_state_active); +} + +void set_mcu_en_gpio_value(int value) +{ + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) + gpio_direction_output(fastchg_di->mcu_en_gpio, value); +} + +void mcu_en_reset(void) +{ + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { + 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)) + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + } else { + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + usleep_range(10000, 10001); + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + } + } +} +#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) { + gpio_direction_output(fastchg_di->usb_sw_1_gpio, 1); + gpio_direction_output(fastchg_di->usb_sw_2_gpio, 1); + } else { + 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)); +} + +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; +} + + +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; +} + +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); + 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_data_active(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}; + int i, rc = 0; + unsigned int addr; + int download_again = 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); + else + rc = dashchg_fw_check(); + if (rc == FW_CHECK_SUCCESS) { + di->firmware_already_updated = true; + reset_mcu_and_request_irq(di); + __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; + } + 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; + 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 */ + di->firmware_already_updated = true; + reset_mcu_and_request_irq(di); + __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); + __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; +} +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) + 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; +} +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, +}; + +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); + 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); +} + +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) + notify_event->op_contrl(status, check_power_ok); +} + +static void update_charger_present_status(struct work_struct *work) +{ + 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) +{ + usb_sw_gpio_set(0); + mcu_en_gpio_set(1); + op_check_charger_collapse_rerun_aicl(); +} + +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_data_active(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]); + 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; + /* switch off fast chg */ + switch_mode_to_normal(); + 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 CURRENT_LIMIT_1 0x1 /* 3.6A */ +#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 */ +#define REJECT_DATA 0x11 + +/* 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); + 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 < 4; i++) { + if (i == 0) { + gpio_set_value(di->ap_data, data >> 2); + } else if (i == 1) { + gpio_set_value(di->ap_data, data >> 1); + } else if (i == 2) { + 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 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; + 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_data_active(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); + 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); + +} + +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)); +} +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) + +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; + + switch (cmd) { + case DASH_NOTIFY_FIRMWARE_UPDATE: + 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; + 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); + } 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; + } + 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; + 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); + } 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); + bq27541_data->set_allow_reading(false); + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + di->is_skin_thermal_medium = check_skin_thermal_medium(); + di->is_skin_temp_high = check_skin_thermal_high(); + di->is_call_on = check_call_on_status(); + if (di->is_skin_temp_high) + dash_write_4bits(di, CURRENT_LIMIT_2); + else if (di->is_skin_thermal_medium && !di->is_skin_temp_high) + dash_write_4bits(di, CURRENT_LIMIT_1); + else if (di->is_call_on) + dash_write_4bits(di, CURRENT_LIMIT_2); + else + dash_write_4bits(di, CURRENT_LIMIT_6); + } + 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; + 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(); + 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(); + 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); + __pm_relax(di->fastchg_wake_lock); + } + break; + case DASH_NOTIFY_ADAPTER_FW_UPDATE: + if (arg == DASH_NOTIFY_ADAPTER_FW_UPDATE + 1) { + di->adapter_update_real + = ADAPTER_FW_NEED_UPDATE; + di->adapter_update_report + = di->adapter_update_real; + } else if (arg == DASH_NOTIFY_ADAPTER_FW_UPDATE + 2) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + oneplus_notify_dash_charger_present(true); + dash_write_4bits(di, ALLOW_DATA); + __pm_stay_awake(di->fastchg_wake_lock); + dash_adapter_update(di); + } + break; + case DASH_NOTIFY_UNDEFINED_CMD: + if (di->fast_chg_started) { + pr_err("UNDEFINED_CMD, switch off fastchg\n"); + switch_mode_to_normal(); + 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(); + 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; + 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; + + dashchg_firmware_data = kmalloc(count, GFP_ATOMIC); + /*malloc for firmware, do not free*/ + if (di->firmware_already_updated) + return 0; + 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->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"); + 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->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_state_active = + pinctrl_lookup_state(di->pinctrl, + "mcu_data_active"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_data_state_active)) { + dev_err(&di->client->dev, + "Can not mcu_data_active state\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_data_state_active); + } + di->pinctrl_mcu_data_state_suspended = + pinctrl_lookup_state(di->pinctrl, + "mcu_data_suspend"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_data_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_mcu_data_state_suspended); + } + } + + 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_state_active) < 0) + pr_err("pinctrl set pinctrl_mcu_data_state_active fail\n"); + + 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"); + } + +} + +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_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"); + } + +} + +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; + + 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); + + 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); + + __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); + 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->ap_clk)) + gpio_free(di->ap_clk); + if (gpio_is_valid(di->ap_data)) + gpio_free(di->ap_data); + + return 0; +} + +static void dash_shutdown(struct i2c_client *client) +{ + usb_sw_gpio_set(0); + mcu_en_reset(); +} + +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/wlchg/Kconfig b/drivers/oneplus/power/supply/wlchg/Kconfig new file mode 100755 index 000000000000..c702fda29d33 --- /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 100755 index 000000000000..48fa48dfaaf9 --- /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 100755 index 000000000000..76edcf808d0f --- /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 100755 index 000000000000..bad78af83e3b --- /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 100755 index 000000000000..99be2f366a3f --- /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 100755 index 000000000000..6d950066ef9b --- /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 100755 index 000000000000..14c242444cbe --- /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 100755 index 000000000000..619f088d4d99 --- /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 100755 index 000000000000..7e9d0d220e19 --- /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 100755 index 000000000000..0092c568420e --- /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 100755 index 000000000000..a6c6eae068af --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.c @@ -0,0 +1,6245 @@ +#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->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; + 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; + 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->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 100755 index 000000000000..1a38f2f2f119 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.h @@ -0,0 +1,474 @@ +#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 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 100755 index 000000000000..4d71e07312f0 --- /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 100755 index 000000000000..3c4976c7d55f --- /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/tri_state_key/Kconfig b/drivers/oneplus/tri_state_key/Kconfig new file mode 100755 index 000000000000..cecfe8cb45e6 --- /dev/null +++ b/drivers/oneplus/tri_state_key/Kconfig @@ -0,0 +1,14 @@ +config TRI_STATE_KEY + default n + 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 000000000000..a54c84da3658 --- /dev/null +++ b/drivers/oneplus/tri_state_key/Makefile @@ -0,0 +1,7 @@ +#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 +obj-y +=hall_ic/ +obj-y +=ist_hall_ic/ +obj-y +=oneplus_tri_key.o 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 000000000000..b6ce56cad6ce --- /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 000000000000..0ccb3ed6e88e --- /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 100755 index 000000000000..af2b467ad337 --- /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 100755 index 000000000000..61ea11e7f6c4 --- /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 100755 index 000000000000..174d292a822d --- /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 000000000000..25cc631d5312 --- /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 000000000000..6aec5ef856fd --- /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 100755 index 000000000000..6650eacf563d --- /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 100755 index 000000000000..8b1292040f66 --- /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 100755 index 000000000000..5d267b7b806d --- /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 000000000000..2a1f80ba9d9f --- /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 000000000000..5f6e249abc3b --- /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 100755 index 000000000000..4e599ed1b461 --- /dev/null +++ b/drivers/oneplus/tri_state_key/tri_state_key.c @@ -0,0 +1,392 @@ +/* + * + * 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}; + int hw_version = 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_LOG("hw_version=%d\n", hw_version); + if (hw_version == 13) { + key[0] = gpio_get_value(extcon_data->key1_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]); + if (key[0] == 1 && key[2] == 1) { + extcon_set_state_sync(extcon_data->edev, 1, 1); + extcon_set_state_sync(extcon_data->edev, 2, 0); + extcon_set_state_sync(extcon_data->edev, 3, 1); + } else if (key[0] == 0 && key[2] == 1) { + 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 if (key[0] == 1 && key[2] == 0) { + extcon_set_state_sync(extcon_data->edev, 1, 1); + extcon_set_state_sync(extcon_data->edev, 2, 1); + extcon_set_state_sync(extcon_data->edev, 3, 0); + } + } else { + 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]) + 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; + 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(unsigned long arg) +{ + 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"); + 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); + 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 100755 index 000000000000..44a5c5a1f810 --- /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 100755 index 000000000000..75c2b031c64f --- /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 100755 index 000000000000..9f5f2fcd6046 --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697.c @@ -0,0 +1,6184 @@ +/* + * 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)) +#define AW8697_LONG_INDEX_HEAD 94 +#define FACTORY_MODE_NORMAL_RTP_NUMBER 82 +#define FACTORY_MODE_HIGH_TEMP_RTP_NUMBER 81 +#define FACTORY_MODE_AT_MODE_RTP_NUMBER 119 + + +/* 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"}, + {"VZW_Alrwave_RTP.bin"}, + {"t-jingle_RTP.bin"}, + {"ringtone_Eager.bin"}, + {"ringtone_Ebullition.bin"}, + {"ringtone_Friendship.bin"}, + {"ringtone_Jazz_life_RTP.bin"}, + {"ringtone_Sun_glittering_RTP.bin"}, + {"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"}, + {"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"}, + {"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 = 83, + 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); + //hrtimer_cancel(&aw8697->timer); + 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); + + 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 != FACTORY_MODE_NORMAL_RTP_NUMBER + && val != FACTORY_MODE_HIGH_TEMP_RTP_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_NORMAL_RTP_NUMBER + || val ==FACTORY_MODE_HIGH_TEMP_RTP_NUMBER) { + if (aw8697->haptic_real_f0 <= 160) + aw8697->rtp_file_num = FACTORY_MODE_160HZ_EFFECTION; + else if (aw8697->haptic_real_f0 <= 162) + aw8697->rtp_file_num = FACTORY_MODE_162HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <=164) + aw8697->rtp_file_num = FACTORY_MODE_164HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 166) + aw8697->rtp_file_num = FACTORY_MODE_166HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 168) + aw8697->rtp_file_num = FACTORY_MODE_168HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 170) + aw8697->rtp_file_num =FACTORY_MODE_170HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 172) + aw8697->rtp_file_num = FACTORY_MODE_172HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 174) + aw8697->rtp_file_num = FACTORY_MODE_174HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 176) + aw8697->rtp_file_num = FACTORY_MODE_176HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 178) + aw8697->rtp_file_num = FACTORY_MODE_178HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= 180) + 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 100755 index 000000000000..6a0ae0c4a9ef --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697.h @@ -0,0 +1,550 @@ +#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 +#define AW8697_HAPTIC_F0_PRE 1700 /* 170Hz*/ +#define AW8697_HAPTIC_F0_CALI_PERCEN 7 /* -7%~7%*/ +#define AW8697_HAPTIC_CONT_DRV_LVL 54 /* value*6.1/256*/ +#define AW8697_HAPTIC_CONT_DRV_LVL_OV 54 /* value*6.1/256*/ +#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 100755 index 000000000000..8a46eb3dee02 --- /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 100755 index 000000000000..3f6f9db5787c --- /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 000000000000..a4a62d819181 --- /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 100755 index 000000000000..45fb25b20c1a --- /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 000000000000..4dd06f8d49f8 --- /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 000000000000..fb24dfb0baaa --- /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 000000000000..01c9aeb2b8a2 --- /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 000000000000..eb3122cb0516 --- /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 000000000000..46239a784864 --- /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 000000000000..e5e166aa2214 --- /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 000000000000..051fcb2b000c --- /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 000000000000..fa6dc8925a55 --- /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 000000000000..0b117491d6ce --- /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 000000000000..abdd4a83ca8a --- /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 000000000000..5b4d9b7f20e3 --- /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 000000000000..1bf727eaf560 --- /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 000000000000..0b2db2ba0e28 --- /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 000000000000..02cba46adb53 --- /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 000000000000..25d84d16240a --- /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 000000000000..952dd16d6019 --- /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 000000000000..48909e091ec3 --- /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 000000000000..7e599ca26e0f --- /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 000000000000..900c7df606cb --- /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 000000000000..53ccad1c112e --- /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 000000000000..0524c0c169f5 --- /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 000000000000..15b5e1276665 --- /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 000000000000..4f9504034bc4 --- /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 000000000000..2a93fe70f330 --- /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 000000000000..37f492699c46 --- /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 000000000000..5b73b703b453 --- /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 000000000000..767367f08217 --- /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 000000000000..c5d70adf68f2 --- /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 000000000000..f9eea814d65f --- /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 000000000000..119d67e0b17e --- /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 000000000000..eb19e3b9bcb4 --- /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 000000000000..34f3652f0a95 --- /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 000000000000..7b8c5b76e2a1 --- /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 000000000000..bb49c457224e --- /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 000000000000..b3b1a98a20ae --- /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 000000000000..8ae39b0fe632 --- /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 000000000000..46f7f0daa5d3 --- /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 000000000000..e00f48830d2d --- /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 000000000000..70266e4418a7 --- /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 000000000000..6d1fa6c3117f --- /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 000000000000..8a8947b6cfe2 --- /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 000000000000..e8e9920e4a36 --- /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 000000000000..5f13482e28e5 --- /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 000000000000..1a0175fa6a3f --- /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 000000000000..b1acfd144577 --- /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 000000000000..21d886e8ae77 --- /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 000000000000..2c3112b841bd --- /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 000000000000..083e53d584a3 --- /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 000000000000..e35f395a233f --- /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 000000000000..3f81932590c2 --- /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 000000000000..6e88cb533de4 --- /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 000000000000..25f14fc467cc --- /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 000000000000..bd21dc8cfa20 --- /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 000000000000..1e3fe3586255 --- /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 000000000000..5a4c004c1ffd --- /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 000000000000..31e75a196deb --- /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 000000000000..af4dc93bf0cc --- /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 000000000000..ecedcb446dda --- /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 000000000000..8c4e99582c91 --- /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 000000000000..0e619422dc2a --- /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 000000000000..12203da232b9 --- /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 000000000000..6a92a3b2c3c2 --- /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 000000000000..742e25aa66da --- /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 000000000000..b187272fe7b3 --- /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 000000000000..b7700a919089 --- /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 000000000000..357e0abb9773 --- /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 000000000000..396d25762a5d --- /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 000000000000..41da1dda1235 --- /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 000000000000..731c48341756 --- /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 000000000000..3d78e2559204 --- /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/pci/controller/pci-msm-msi.c b/drivers/pci/controller/pci-msm-msi.c index 61c211e0d862..5cadb2dcc83f 100644 --- a/drivers/pci/controller/pci-msm-msi.c +++ b/drivers/pci/controller/pci-msm-msi.c @@ -386,6 +386,11 @@ int msm_msi_init(struct device *dev) for (i = 0; i < msi->nr_irqs; i++) { unsigned int irq = irq_of_parse_and_map(msi->of_node, i); + struct irq_desc *desc; + const char *devname; + static const char rc0_name[] = "1c00000.qcom,pcie"; + /* static const char rc1_name[] = "1c08000.qcom,pcie"; */ + static const char rc2_name[] = "1c10000.qcom,pcie"; if (!irq) { dev_err(msi->dev, @@ -397,6 +402,14 @@ int msm_msi_init(struct device *dev) msi->irqs[i].hwirq = irq; irq_set_chained_handler_and_data(msi->irqs[i].hwirq, msm_msi_handler, msi); + desc = irq_to_desc(irq); + devname = kobject_name(&dev->kobj); + if (strncmp(devname, rc0_name, 17) == 0) /* pcie0: qcom,pcie@1c00000 */ + desc->action->name = "qcommsi-rc0"; + else if (strncmp(devname, rc2_name, 17) == 0) /* pcie2: qcom,pcie@1c10000 */ + desc->action->name = "qcommsi-rc2"; + else + desc->action->name = "qcommsi-rc1"; /* pcie1£ºqcom,pcie@1c08000 */ } return 0; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index f8ce0eac1ae8..beb2f233c630 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++) + seq_puts(s, " name dir val fun drv pull \n"); + + for (i = 0; i < chip->ngpio; i++, gpio++) { + + if (i == 28 || i == 29 || i == 30 || i == 31 || + i == 40 || i == 41 || i == 42 || i == 43 ) + continue; msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); + } } #else diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index cfe36b44889d..8d608d3fb8a2 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -792,6 +792,8 @@ static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) struct pmic_gpio_state *state = gpiochip_get_data(chip); unsigned i; + seq_puts(s, "\n name : dir func p_s biases buffer_types val strength atest dtest\n"); + for (i = 0; i < chip->ngpio; i++) { pmic_gpio_config_dbg_show(state->ctrl, s, i); seq_puts(s, "\n"); diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e6..62e35fba7929 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 @@ -40,6 +41,8 @@ #define SCM_DLOAD_CMD 0x10 #define SCM_DLOAD_MINIDUMP 0X20 #define SCM_DLOAD_BOTHDUMPS (SCM_DLOAD_MINIDUMP | SCM_DLOAD_FULLDUMP) +#define OEM_FUSION_MODEMDUMP 0 +#define OEM_TWICE_MODEMDUMP 1 #define DL_MODE_PROP "qcom,msm-imem-download_mode" #define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode" @@ -67,6 +70,7 @@ static struct kobject dload_kobj; static int in_panic; static int dload_type = SCM_DLOAD_FULLDUMP; +static int oem_modemdump_type = OEM_FUSION_MODEMDUMP; static void *dload_mode_addr; static bool dload_mode_enabled; static void *emergency_dload_mode_addr; @@ -103,11 +107,18 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, RESET_ATTR(dload_mode, 0644, show_dload_mode, store_dload_mode); #endif /* CONFIG_QCOM_MINIDUMP */ +static ssize_t show_oem_modemdump(struct kobject *kobj, struct attribute *attr, + char *buf); +static size_t store_oem_modemdump(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count); +RESET_ATTR(oem_modemdump, 0644, show_oem_modemdump, store_oem_modemdump); + static struct attribute *reset_attrs[] = { &reset_attr_emmc_dload.attr, #ifdef CONFIG_QCOM_MINIDUMP &reset_attr_dload_mode.attr, #endif + &reset_attr_oem_modemdump.attr, NULL }; @@ -132,6 +143,18 @@ 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); +} +EXPORT_SYMBOL(oem_get_download_mode); + +int oem_get_modemdump_mode(void) +{ + return oem_modemdump_type; +} +EXPORT_SYMBOL(oem_get_modemdump_mode); + static int panic_prep_restart(struct notifier_block *this, unsigned long event, void *ptr) { @@ -165,8 +188,16 @@ int scm_set_dload_mode(int arg1, int arg2) static void set_dload_mode(int on) { int ret; - - if (dload_mode_addr) { + u64 read_ret; + /* OEM : Set dload_mode to cust value when twice modemdump is triggered */ + pr_err("[MDM] twice modemdump state [%d]\n", oem_get_twice_modemdump_state()); + if (dload_mode_addr && oem_get_twice_modemdump_state()) { + __raw_writel(on ? 0xABCDABCD : 0, dload_mode_addr); + /* Make sure the download cookie is updated */ + mb(); + read_ret = __raw_readl(dload_mode_addr); + pr_err("[MDM] dload_mode value [0x%X]\n", read_ret); + } else if (dload_mode_addr) { __raw_writel(on ? 0xE47B337D : 0, dload_mode_addr); __raw_writel(on ? 0xCE14091A : 0, dload_mode_addr + sizeof(unsigned int)); @@ -186,6 +217,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; @@ -422,6 +463,29 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, } #endif /* CONFIG_QCOM_MINIDUMP */ +static ssize_t show_oem_modemdump(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "oem modemdump: %s\n", + (oem_modemdump_type == OEM_TWICE_MODEMDUMP) ? "twice" : "fusion"); +} + +static size_t store_oem_modemdump(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + if (sysfs_streq(buf, "twice")) { + oem_modemdump_type = OEM_TWICE_MODEMDUMP; + pr_err("[MDM] Modemdump : twice\n"); + } else if (sysfs_streq(buf, "fusion")) { + oem_modemdump_type = OEM_FUSION_MODEMDUMP; + pr_err("[MDM] Modemdump : fusion\n"); + } else { + pr_err("[MDM] Invalid modemdump setup request..\n"); + return -EINVAL; + } + return count; +} + static void scm_disable_sdi(void) { int ret; @@ -520,6 +584,30 @@ 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, "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 if (!strncmp(cmd, "oem-", 4)) { unsigned long code; int ret; diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index bcacfd977d14..3deae85113a9 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -283,6 +283,28 @@ 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), + 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), @@ -375,6 +397,10 @@ 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(apsd_not_done), + POWER_SUPPLY_ATTR(remaining_capacity), POWER_SUPPLY_ATTR(resistance), POWER_SUPPLY_ATTR(resistance_capacitive), POWER_SUPPLY_ATTR(resistance_id), @@ -481,6 +507,14 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(cp_ilim), POWER_SUPPLY_ATTR(irq_status), POWER_SUPPLY_ATTR(parallel_output_mode), + POWER_SUPPLY_ATTR(cp_disable_cur_sens), + POWER_SUPPLY_ATTR(wireless_mode), + POWER_SUPPLY_ATTR(wireless_type), + POWER_SUPPLY_ATTR(tx_voltage_now), + POWER_SUPPLY_ATTR(tx_current_now), + POWER_SUPPLY_ATTR(cp_voltage_now), + POWER_SUPPLY_ATTR(cp_current_now), + POWER_SUPPLY_ATTR(icon_delay), POWER_SUPPLY_ATTR(fg_type), POWER_SUPPLY_ATTR(charger_status), /* Local extensions of type int64_t */ diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index ec45b7d1c502..e7938cabeb7b 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -77,6 +77,7 @@ struct pl_data { struct power_supply *dc_psy; struct power_supply *cp_master_psy; struct power_supply *cp_slave_psy; + struct power_supply *op_chg_psy; int charge_type; int total_settled_ua; int pl_settled_ua; @@ -193,8 +194,7 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode) static int get_adapter_icl_based_ilim(struct pl_data *chip) { - int main_icl = -EINVAL, adapter_icl = -EINVAL, final_icl = -EINVAL; - int rc = -EINVAL; + int main_icl, adapter_icl = -EINVAL, rc = -EINVAL, final_icl = -EINVAL; union power_supply_propval pval = {0, }; rc = power_supply_get_property(chip->usb_psy, @@ -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_err("fv_uv=%d\n", fv_uv); rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); if (rc < 0) { @@ -1301,10 +1302,10 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, */ if (icl_ua <= 1400000) vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); - else + else { schedule_delayed_work(&chip->status_change_work, msecs_to_jiffies(PL_DELAY_MS)); - + } /* rerun AICL */ /* get the settled current */ rc = power_supply_get_property(chip->main_psy, @@ -1915,9 +1916,9 @@ static int pl_notifier_call(struct notifier_block *nb, if ((strcmp(psy->desc->name, "parallel") == 0) || (strcmp(psy->desc->name, "battery") == 0) - || (strcmp(psy->desc->name, "main") == 0)) + || (strcmp(psy->desc->name, "main") == 0)) { schedule_delayed_work(&chip->status_change_work, 0); - + } return NOTIFY_OK; } diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index aa3c9b13c999..739485aa4554 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -477,6 +477,7 @@ struct fg_dev { bool profile_available; enum prof_load_status profile_load_status; bool battery_missing; + bool use_external_fg; bool fg_restarting; bool charge_full; bool recharge_soc_adjusted; diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index 0d152d57258e..6936056a3428 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -378,39 +378,35 @@ bool is_input_present(struct fg_dev *fg) return is_usb_present(fg) || is_dc_present(fg); } -void fg_notify_charger(struct fg_dev *fg) +void fg_notify_charger(struct fg_dev *chip) { union power_supply_propval prop = {0, }; int rc; - if (!fg->batt_psy) + if (!chip->batt_psy) return; - if (!fg->profile_available) + if (!chip->profile_available) return; - if (fg->bp.float_volt_uv > 0) { - prop.intval = fg->bp.float_volt_uv; - rc = power_supply_set_property(fg->batt_psy, - POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop); - if (rc < 0) { - pr_err("Error in setting 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); + if (rc < 0) { + pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n", + rc); + return; } - if (fg->bp.fastchg_curr_ma > 0) { - prop.intval = fg->bp.fastchg_curr_ma * 1000; - rc = power_supply_set_property(fg->batt_psy, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, - &prop); - if (rc < 0) { - pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n", - rc); - return; - } + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_NOTIFY_CHARGER_SET_PARAMETER, &prop); + if (rc < 0) { + pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n", + rc); + return; } + + fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n"); } bool batt_psy_initialized(struct fg_dev *fg) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 9c179be4816f..b6bdeba7ba2f 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -20,6 +20,7 @@ #include "fg-core.h" #include "fg-reg.h" #include "fg-alg.h" +#include #define FG_GEN4_DEV_NAME "qcom,fg-gen4" #define TTF_AWAKE_VOTER "fg_ttf_awake" @@ -171,6 +172,14 @@ #define MONOTONIC_SOC_WORD 463 #define MONOTONIC_SOC_OFFSET 0 +static void oem_update_cc_cv_setpoint(struct fg_dev *chip, + int cv_float_point); +static void oneplus_set_allow_read_iic(struct fg_dev *chip, + bool status); +static void oneplus_set_lcd_off_status(struct fg_dev *chip, + bool status); +static struct external_battery_gauge *external_fg; + /* v2 SRAM address and offset in ascending order */ #define LOW_PASS_VBATT_WORD 3 #define LOW_PASS_VBATT_OFFSET 0 @@ -373,6 +382,24 @@ static ssize_t sram_dump_period_ms_store(struct device *dev, } static DEVICE_ATTR_RW(sram_dump_period_ms); +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); + static int fg_restart_mp; static bool fg_sram_dump; static bool fg_esr_fast_cal_en; @@ -631,6 +658,8 @@ static int fg_get_batt_id_adc(struct fg_gen4_chip *chip, u32 *batt_id_ohms) } #define MAX_BIAS_CODE 0x70E4 + +#define OP_SW_DEFAULT_ID 200000 static int fg_gen4_get_batt_id(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; @@ -680,7 +709,8 @@ static int fg_gen4_get_batt_id(struct fg_gen4_chip *chip) */ batt_id_kohms = (id_table[bias_id].bias_kohms * bias_code) * 10 / (MAX_BIAS_CODE - bias_code); - fg->batt_id_ohms = (batt_id_kohms * 1000) / 10; + + fg->batt_id_ohms = OP_SW_DEFAULT_ID; return 0; } @@ -2749,14 +2779,14 @@ static int fg_gen4_update_maint_soc(struct fg_dev *fg) goto out; } - if (msoc >= fg->maint_soc) { + if (msoc > fg->maint_soc) { /* * When the monotonic SOC goes above maintenance SOC, we should * stop showing the maintenance SOC. */ fg->delta_soc = 0; fg->maint_soc = 0; - } else if (fg->maint_soc && msoc < fg->last_msoc) { + } else if (fg->maint_soc && msoc <= fg->last_msoc) { /* MSOC is decreasing. Decrease maintenance SOC as well */ fg->maint_soc -= 1; if (!(msoc % 10)) { @@ -2777,6 +2807,8 @@ out: return rc; } +#define DEFALUT_BATT_TEMP 250 + static int fg_gen4_configure_full_soc(struct fg_dev *fg, int bsoc) { int rc; @@ -3843,7 +3875,7 @@ static struct fg_irq_info fg_irqs[FG_GEN4_IRQ_MAX] = { [ESR_DELTA_IRQ] = { .name = "esr-delta", .handler = fg_delta_esr_irq_handler, - .wakeable = true, + /*.wakeable = true,*//*op disable ers calibration*/ }, [VBATT_LOW_IRQ] = { .name = "vbatt-low", @@ -4145,6 +4177,7 @@ static void pl_current_en_work(struct work_struct *work) return; vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0); + vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); } static void pl_enable_work(struct work_struct *work) @@ -4467,7 +4500,13 @@ static int fg_psy_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: - rc = fg_gen4_get_prop_capacity(fg, &pval->intval); + if (!get_extern_fg_regist_done()) + pval->intval = get_prop_pre_shutdown_soc(); + else if (fg->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_REAL_CAPACITY: rc = fg_gen4_get_prop_real_capacity(fg, &pval->intval); @@ -4485,19 +4524,32 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = div_s64((int64_t)val * 10000, CC_SOC_30BIT); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - if (fg->battery_missing) - pval->intval = 3700000; + if (fg->use_external_fg && external_fg + && external_fg->get_battery_mvolts) + pval->intval = external_fg->get_battery_mvolts(); else - rc = fg_get_battery_voltage(fg, &pval->intval); + pval->intval = 4000000; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = fg_get_battery_current(fg, &pval->intval); + if (fg->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_CURRENT_AVG: rc = fg_get_sram_prop(fg, FG_SRAM_IBAT_FLT, &pval->intval); break; case POWER_SUPPLY_PROP_TEMP: - rc = fg_gen4_get_battery_temp(fg, &pval->intval); + if (!get_extern_fg_regist_done() + && get_extern_bq_present()) + pval->intval = DEFALUT_BATT_TEMP; + else if (fg->use_external_fg && external_fg + && external_fg->get_battery_temperature) { + pval->intval = + external_fg->get_battery_temperature(); + } else + pval->intval = -400; break; case POWER_SUPPLY_PROP_RESISTANCE: rc = fg_get_battery_resistance(fg, &pval->intval); @@ -4530,14 +4582,28 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = chip->cl->init_cap_uah; break; case POWER_SUPPLY_PROP_CHARGE_FULL: - rc = fg_gen4_get_learned_capacity(chip, &temp); - if (!rc) - pval->intval = (int)temp; + if (!get_extern_fg_regist_done() && get_extern_bq_present()) + pval->intval = -EINVAL; + else if (fg->use_external_fg && external_fg && external_fg->get_batt_full_chg_capacity) + pval->intval = external_fg->get_batt_full_chg_capacity(); + else { + rc = fg_gen4_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 (fg->use_external_fg && external_fg && external_fg->get_batt_remaining_capacity) + pval->intval = external_fg->get_batt_remaining_capacity(); + else + pval->intval = -EINVAL; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: rc = fg_gen4_get_nominal_capacity(chip, &temp); if (!rc) - pval->intval = (int)temp; + pval->intval = -EINVAL; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = fg_gen4_get_charge_counter(chip, &pval->intval); @@ -4565,6 +4631,25 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_DEBUG_BATTERY: pval->intval = is_debug_batt_id(fg); break; + case POWER_SUPPLY_PROP_FG_CAPACITY: + rc = fg_gen4_get_prop_capacity(fg, &pval->intval); + break; + case POWER_SUPPLY_PROP_FG_VOLTAGE_NOW: + if (fg->battery_missing) + pval->intval = 3700000; + else + rc = fg_get_battery_voltage(fg, &pval->intval); + break; + case POWER_SUPPLY_PROP_FG_CURRENT_NOW: + rc = fg_get_battery_current(fg, &pval->intval); + break; + case POWER_SUPPLY_PROP_BQ_SOC: + if (fg->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_CONSTANT_CHARGE_VOLTAGE: rc = fg_get_sram_prop(fg, FG_SRAM_VBATT_FULL, &pval->intval); break; @@ -4625,6 +4710,16 @@ static int fg_psy_set_property(struct power_supply *psy, u8 val, mask; switch (psp) { + case POWER_SUPPLY_PROP_CC_TO_CV_POINT: + oem_update_cc_cv_setpoint(&chip->fg, pval->intval); + break; + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: + oneplus_set_allow_read_iic(&chip->fg, pval->intval); + break; + case POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF: + oneplus_set_lcd_off_status(&chip->fg, pval->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: if (chip->cl->active) { pr_warn("Capacity learning active!\n"); @@ -4714,6 +4809,7 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_ESR_ACTUAL: case POWER_SUPPLY_PROP_ESR_NOMINAL: case POWER_SUPPLY_PROP_SOH: + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: case POWER_SUPPLY_PROP_CLEAR_SOH: case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: case POWER_SUPPLY_PROP_CALIBRATE: @@ -4763,6 +4859,9 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_SCALE_MODE_EN, POWER_SUPPLY_PROP_CALIBRATE, + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, + POWER_SUPPLY_PROP_BQ_SOC, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, }; static const struct power_supply_desc fg_psy_desc = { @@ -4885,7 +4984,7 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data, pr_err("Error in writing to 0x%04x, rc=%d\n", BATT_INFO_FG_CNV_CHAR_CFG(fg), rc); - vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); + //vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); fg_dbg(fg, FG_STATUS, "Parallel current summing: %d\n", enable); return rc; @@ -4910,6 +5009,7 @@ static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data, return 0; } +static bool esr_irq_is_en; static int fg_gen4_delta_esr_irq_en_cb(struct votable *votable, void *data, int enable, const char *client) { @@ -4919,11 +5019,17 @@ static int fg_gen4_delta_esr_irq_en_cb(struct votable *votable, void *data, return 0; if (enable) { - enable_irq(fg->irqs[ESR_DELTA_IRQ].irq); - enable_irq_wake(fg->irqs[ESR_DELTA_IRQ].irq); + if (!esr_irq_is_en) { + esr_irq_is_en = true; + enable_irq(fg->irqs[ESR_DELTA_IRQ].irq); + enable_irq_wake(fg->irqs[ESR_DELTA_IRQ].irq); + } } else { - disable_irq_wake(fg->irqs[ESR_DELTA_IRQ].irq); - disable_irq_nosync(fg->irqs[ESR_DELTA_IRQ].irq); + if (esr_irq_is_en) { + esr_irq_is_en = false; + disable_irq_wake(fg->irqs[ESR_DELTA_IRQ].irq); + disable_irq_nosync(fg->irqs[ESR_DELTA_IRQ].irq); + } } return 0; @@ -5435,6 +5541,13 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) return rc; } + rc = fg_masked_write(fg, + BATT_INFO_ESR_PULL_DN_CFG(fg), 0xFF, 0); + if (rc < 0) { + pr_err("Error in writing ESR PULL DN, rc=%d\n", rc); + return rc; + } + if (is_debug_batt_id(fg)) { val = ESR_NO_PULL_DOWN; rc = fg_masked_write(fg, BATT_INFO_ESR_PULL_DN_CFG(fg), @@ -6055,6 +6168,10 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); + fg->use_external_fg = + of_property_read_bool(node, "oem,use_external_fg"); + pr_info("use_external_fg=%d\n", fg->use_external_fg); + fg_gen4_parse_cl_params_dt(chip); fg_gen4_parse_batt_temp_dt(chip); @@ -6133,6 +6250,9 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; + if (fg->fg_psy) + power_supply_unregister(fg->fg_psy); + fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); cancel_work_sync(&fg->status_change_work); @@ -6165,6 +6285,32 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) dev_set_drvdata(fg->dev, NULL); } +static void oem_update_cc_cv_setpoint( + struct fg_dev *chip, int cv_float_point) +{ + /* TODO: write CC_CV_SETPOINT_REG */ +} + +static void oneplus_set_allow_read_iic(struct fg_dev *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 fg_dev *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 void fg_gen4_post_init(struct fg_gen4_chip *chip) { int i; diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index a608c7a3c251..007815fbaed3 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -3,6 +3,8 @@ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ +#define pr_fmt(fmt) "SMB2: %s: " fmt, __func__ + #include #include #include @@ -19,6 +21,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include "smb5-reg.h" #include "smb5-lib.h" @@ -150,6 +157,13 @@ static struct smb_params smb5_pm8150b_params = { .max_u = 3000000, .step_u = 500000, }, + .otg_vol = { + .name = "usb otg output voltage", + .reg = DCDC_VBOOST_CFG, + .min_u = 4800000, + .max_u = 5500000, + .step_u = 100000, + }, .dc_icl = { .name = "DC input current limit", .reg = DCDC_CFG_REF_MAX_PSNS_REG, @@ -227,7 +241,41 @@ struct smb5 { struct smb_dt_props dt; }; +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 +334,26 @@ 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 +); + enum { BAT_THERM = 0, MISC_THERM, @@ -443,6 +511,13 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) { int rc = 0, byte_len; struct smb_charger *chg = &chip->chg; + enum of_gpio_flags flags; + int retval = 0; + + 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 +529,350 @@ 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); + + OF_PROP_READ(node, "op,skin-thermal-high-threshold", + chg->skin_thermal_high_threshold, retval, 1); + if (chg->skin_thermal_high_threshold <= 0) + chg->skin_thermal_high_threshold = + SKIN_THERMAL_HIGH; + pr_info("skin_thermal_high_threshold=%d\n", + chg->skin_thermal_high_threshold); + + OF_PROP_READ(node, "op,skin-thermal-pre-high-threshold", + chg->skin_thermal_pre_high_threshold, retval, 1); + if (chg->skin_thermal_pre_high_threshold <= 0) + chg->skin_thermal_pre_high_threshold = + SKIN_THERMAL_PRE_HIGH; + pr_info("skin_thermal_pre_high_threshold=%d\n", + chg->skin_thermal_pre_high_threshold); + + OF_PROP_READ(node, "op,skin-thermal-medium-threshold", + chg->skin_thermal_medium_threshold, retval, 1); + if (chg->skin_thermal_medium_threshold <= 0) + chg->skin_thermal_medium_threshold = + SKIM_THERMAL_MEDIUM; + pr_info("skin_thermal_medium_threshold=%d\n", + chg->skin_thermal_medium_threshold); + + OF_PROP_READ(node, "op,skin-thermal-normal-threshold", + chg->skin_thermal_normal_threshold, retval, 1); + if (chg->skin_thermal_normal_threshold <= 0) + chg->skin_thermal_normal_threshold = + SKIN_THERMAL_NORMAL; + pr_info("skin_thermal_normal_threshold=%d\n", + chg->skin_thermal_normal_threshold); + + 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); + + 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); + chg->check_slow_charge = of_property_read_bool(node, + "op,slowy-charge-check"); + pr_info("op,slowy-charge-check=%d\n", + chg->check_slow_charge); + + 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 +898,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 +995,58 @@ 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; + rc = of_property_match_string(node, "io-channel-names", + "gpio1_voltage"); + if (rc >= 0) { + chg->iio.op_connector_temp_chan = iio_channel_get(chg->dev, + "gpio1_voltage"); + 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", + "gpio8_voltage"); + if (rc >= 0) { + chg->iio.op_connector_temp_chan_sec = iio_channel_get(chg->dev, + "gpio8_voltage"); + 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"); - + 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 +1122,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 +1302,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; @@ -851,6 +1357,9 @@ 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, + 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, @@ -930,11 +1439,22 @@ 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; + 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); + 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); @@ -1076,6 +1596,10 @@ 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; + 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; @@ -1156,6 +1680,7 @@ static int smb5_usb_prop_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { + 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 +1751,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 +2225,19 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_APSD_NOT_DONE, + 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, @@ -1726,6 +2267,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_FORCE_RECHARGE, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, }; #define DEBUG_ACCESSORY_TEMP_DECIDEGC 250 @@ -1738,7 +2280,10 @@ 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); + 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); @@ -1755,6 +2300,45 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_get_prop_batt_capacity(chg, val); break; + 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_APSD_NOT_DONE: + val->intval = chg->apsd_not_done || chg->slow_charger; + 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; @@ -1812,8 +2396,7 @@ static int smb5_batt_get_prop(struct power_supply *psy, if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY) val->intval = DEBUG_ACCESSORY_TEMP_DECIDEGC; else - rc = smblib_get_prop_from_bms(chg, - POWER_SUPPLY_PROP_TEMP, val); + rc = smblib_get_prop_batt_temp(chg, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1900,6 +2483,99 @@ 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; + 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_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; + if (!chg->wls_psy) + chg->wls_psy = power_supply_get_by_name("wireless"); + if (chg->wls_psy) { + rc = power_supply_set_property(chg->wls_psy, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, val); + if (rc < 0) + pr_err("Couldn't disable wireless charge, rc=%d\n", rc); + } + pr_info("user set disable chg %d\n", val->intval); + break; + case POWER_SUPPLY_PROP_APSD_NOT_DONE: + chg->apsd_not_done = (bool)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; @@ -1992,12 +2668,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: + 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: + case POWER_SUPPLY_PROP_APSD_NOT_DONE: return 1; default: break; @@ -2129,6 +2815,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); @@ -2185,14 +2872,30 @@ static int smb5_configure_typec(struct smb_charger *chg) } } + 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); + 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, @@ -2203,16 +2906,37 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } + 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); if (rc < 0) { dev_err(chg->dev, - "Couldn't configure TYPE_C_MODE_CFG_REG rc=%d\n", rc); + "Couldn't configure TYPE_C_MODE_CFG_REG rc=%d\n", + rc); return rc; } chg->typec_try_mode |= EN_TRY_SNK_BIT; +*/ /* For PD capable targets configure VCONN for software control */ if (!chg->pd_not_supported) { @@ -2685,6 +3409,11 @@ static int smb5_init_hw(struct smb5 *chip) smblib_get_charge_param(chg, &chg->param.usb_icl, &chg->default_icl_ua); + + 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; @@ -2752,6 +3481,14 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } + 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) { @@ -2779,6 +3516,18 @@ 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); + /* 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) @@ -3460,6 +4209,245 @@ static void smb5_create_debugfs(struct smb5 *chip) #endif +#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_threld_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, + chg->skin_thermal_pre_high_threshold, + chg->skin_thermal_medium_threshold, + chg->skin_thermal_normal_threshold); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_skin_threld_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 = hi_val; + chg->skin_thermal_pre_high_threshold = pre_hi_val; + chg->skin_thermal_medium_threshold = med_val; + chg->skin_thermal_normal_threshold = 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_threld_ops = { + .read = proc_skin_threld_read, + .write = proc_skin_threld_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +/* @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); + vote(chip->fcc_votable, FCC_STEPPER_VOTER, false, 0); + chip->hw_detect = 1; + chip->pre_cable_pluged = 1; + ret = plugin_update(chip); + pr_info("%s:hw_detect=%d and report rc: %d\n", + __func__, chip->hw_detect, ret); + } else + chip->pre_cable_pluged = 0; +} + static int smb5_show_charger_status(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; @@ -3537,16 +4525,24 @@ 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; + 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->mode = PARALLEL_MASTER; chg->irq_info = smb5_irqs; chg->die_health = -EINVAL; @@ -3589,6 +4585,14 @@ static int smb5_probe(struct platform_device *pdev) /* set driver data before resources request it */ platform_set_drvdata(pdev, chip); + op_charge_info_init(chg); + 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)) { @@ -3727,8 +4731,36 @@ static int smb5_probe(struct platform_device *pdev) goto free_irq; } +#ifdef CONFIG_PROC_FS + if (!proc_create("ship_mode", 0644, NULL, &proc_ship_mode_operations)) + pr_err("Failed to register proc interface\n"); +#endif + if (!proc_create("chg_skin_thermal_thd", 0644, NULL, &proc_skin_threld_ops)) + pr_err("Failed to register chg_skin_thermal_thd proc interface\n"); + + 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); + op_ship_mode_gpio_request(chg); + requset_vbus_ctrl_gpio(chg); + op_config_usb_temperature_adc(chg); + request_plug_irq(chg); + exchg_information_register(chg); + chg->probe_done = true; pr_info("QPNP SMB5 probed successfully\n"); return rc; @@ -3759,11 +4791,45 @@ static int smb5_remove(struct platform_device *pdev) return 0; } +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; +#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/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 7818896c62c9..3f0ab3e955a8 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2,6 +2,10 @@ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ +#define pr_fmt(fmt) "SMBLIB: %s: " fmt, __func__ + +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB #include #include @@ -19,7 +23,73 @@ #include "schgm-flash.h" #include "step-chg-jeita.h" #include "storm-watch.h" -#include "schgm-flash.h" + +#include +#include +#include +#include +#include +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_MSM_RDM_NOTIFY) +#include +#include +#include +#endif /*CONFIG_FB*/ +#include +#include +#include +#include +#include + +#define SOC_INVALID 0x7E +#define SOC_DATA_REG_0 0x88D +#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 + +struct smb_charger *g_chg; +struct regmap *pm_regmap; + +static struct external_battery_gauge *fast_charger; +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); +static int get_usb_temp(struct smb_charger *chg); +static void op_clean_dash_status(void); +static void op_typec_state_change_irq_handler(void); +static int sys_boot_complete; +static int usb_enum_check(const char *val, const struct kernel_param *kp); +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, \ @@ -177,6 +247,11 @@ int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode) icl_override = 0; apsd_override = ICL_OVERRIDE_AFTER_APSD_BIT; break; + case SW_OVERRIDE_WIRELESS_MODE: + usb51_mode = USBIN_MODE_CHG_BIT; + icl_override = ICL_OVERRIDE_BIT; + apsd_override = ICL_OVERRIDE_AFTER_APSD_BIT; + break; case HW_AUTO_MODE: default: usb51_mode = USBIN_MODE_CHG_BIT; @@ -371,6 +446,41 @@ static void smblib_notify_usb_host(struct smb_charger *chg, bool enable) extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable); } +#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; + + if (chg->wireless_present) { + pr_info("wireless charge needn't rerun apsd\n"); + return 0; + } + + 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 +623,7 @@ static const struct apsd_result smblib_apsd_results[] = { [FLOAT] = { .name = "FLOAT", .bit = FLOAT_CHARGER_BIT, - .pst = POWER_SUPPLY_TYPE_USB_FLOAT + .pst = POWER_SUPPLY_TYPE_USB_DCP }, [HVDCP2] = { .name = "HVDCP2", @@ -539,10 +649,10 @@ 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)) + 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", @@ -555,7 +665,6 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) if (smblib_apsd_results[i].bit == stat) result = &smblib_apsd_results[i]; } - if (apsd_stat & QC_CHARGER_BIT) { /* since its a qc_charger, either return HVDCP3 or HVDCP2 */ if (result != &smblib_apsd_results[HVDCP3]) @@ -721,6 +830,20 @@ int smblib_set_charge_param(struct smb_charger *chg, int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; + 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 +864,7 @@ 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; + pr_info("%d\n", suspend); rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT, suspend ? DCIN_SUSPEND_BIT : 0); @@ -751,6 +875,90 @@ int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend) return rc; } +#define MICRO_5V 5000000 +#define MICRO_9V 9000000 +#define MICRO_12V 12000000 +static int op_set_wireless_fsw(struct smb_charger *chg, int voltage) +{ + int rc = 0; + + if (voltage == MICRO_5V) + rc = smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_6V_8V); + else if (voltage > MICRO_5V && voltage < MICRO_9V) + rc = smblib_set_opt_switcher_freq(chg, + chg->chg_freq.freq_6V_8V); + else if (voltage >= MICRO_9V && voltage < MICRO_12V) + rc = smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_12V); + else if (voltage == MICRO_12V) + rc = smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_12V); + else { + smblib_err(chg, "Couldn't set Fsw: invalid voltage %d\n", + voltage); + return -EINVAL; + } + + return rc; +} + +/* @bsp, 2019/08/30 Wireless Charging porting */ +int op_wireless_high_vol_en(bool enable) +{ + int rc; + static bool reconfiged_aicl; + + g_chg->wireless_high_vol_mode = enable; + smblib_hvdcp_detect_enable(g_chg, enable); + rc = smblib_write(g_chg, USBIN_ADAPTER_ALLOW_CFG_REG, + enable ? USBIN_ADAPTER_ALLOW_5V_TO_12V : + USBIN_ADAPTER_ALLOW_5V); + if (rc < 0) { + smblib_err(g_chg, + "Couldn't write USBIN_ADAPTER_ALLOW_CFG_REG, rc=%d\n", + rc); + return rc; + } + + if (g_chg->wireless_present) { + rc = op_set_wireless_fsw(g_chg, enable ? MICRO_9V : MICRO_5V); + if (rc < 0) { + smblib_err(g_chg, "Couldn't set buck freq, rc=%d\n", rc); + return rc; + } + + if (!reconfiged_aicl) { + // usbin collapse keep FET on. + rc = smblib_masked_write(g_chg, USBIN_AICL_OPTIONS_CFG_REG, + USBIN_AICL_EN_BIT | USBIN_HV_COLLAPSE_RESPONSE_BIT + | USBIN_LV_COLLAPSE_RESPONSE_BIT, USBIN_AICL_EN_BIT); + if (rc < 0) { + smblib_err(g_chg, "Couldn't turn on USBIN_AICL_OPTIONS_CFG_REG AICL rc=%d\n", + rc); + return rc; + } + rc = smblib_masked_write(g_chg, USBIN_LOAD_CFG_REG, + USBIN_AICL_STEP_TIMING_SEL_MASK | USBIN_IN_COLLAPSE_GF_SEL_MASK, + USBIN_AICL_STEP_TIMING_SEL_MASK | BIT(1)); + if (rc < 0) { + smblib_err(g_chg, "Couldn't turn on USBIN_LOAD_CFG_REG rc=%d\n", rc); + return rc; + } + reconfiged_aicl = true; + } + } else { + reconfiged_aicl = false; + // restore usbin aicl step timing. + rc = smblib_masked_write(g_chg, USBIN_LOAD_CFG_REG, + USBIN_AICL_STEP_TIMING_SEL_MASK | USBIN_IN_COLLAPSE_GF_SEL_MASK, + 0); + if (rc < 0) { + smblib_err(g_chg, "Couldn't turn on USBIN_LOAD_CFG_REG rc=%d\n", rc); + return rc; + } + } + + return rc; +} + static int smblib_usb_pd_adapter_allowance_override(struct smb_charger *chg, u8 allowed_voltage) { @@ -759,6 +967,11 @@ static int smblib_usb_pd_adapter_allowance_override(struct smb_charger *chg, if (chg->chg_param.smb_version == PMI632_SUBTYPE) return 0; + if (chg->wireless_high_vol_mode) { + smblib_dbg(chg, PR_MISC, "Wireless high voltage mode, exit\n"); + return 0; + } + rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_OVERRIDE_REG, allowed_voltage); if (rc < 0) @@ -1085,23 +1298,25 @@ 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; + if (chg->dash_on) { + chg->real_charger_type = POWER_SUPPLY_TYPE_DASH; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_DASH; + } else if (chg->wireless_present) { + chg->real_charger_type = POWER_SUPPLY_TYPE_WIRELESS; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_WIRELESS; } 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); + if (chg->pd_active) + notify_pd_in_to_wireless(); + + 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 +1429,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 +1624,62 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return rc; } +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 +1687,10 @@ 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); + pr_info("icl_ua=%d\n", icl_ua); + smblib_err(chg, "icl_ua=%d, connector_type=%d, real_charger_type=%d\n", + icl_ua, chg->connector_type, chg->real_charger_type); + if (chg->chg_param.smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, suspend ? TORCH_BOOST_MODE : TORCH_BUCK_MODE); @@ -1437,11 +1711,31 @@ 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)) { + 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); goto out; } + } else if (chg->wireless_present) { + if (icl_ua <= USBIN_500MA) { + rc = set_sdp_current(chg, icl_ua); + if (rc >= 0) + goto unsuspend; + } + + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't set wireless ICL rc=%d\n", rc); + goto out; + } + icl_override = SW_OVERRIDE_WIRELESS_MODE; } else { /* * Try USB 2.0/3,0 option first on USB path when maximum input @@ -1669,11 +1963,31 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } +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; + pr_info("set awake=%d\n", awake); if (awake) pm_stay_awake(chg->dev); else @@ -1688,6 +2002,7 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data, struct smb_charger *chg = data; int rc; + 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 +2494,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 +2508,7 @@ 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; - } - } + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat); @@ -2229,7 +2528,6 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, else val->intval = POWER_SUPPLY_HEALTH_GOOD; -done: return rc; } @@ -2313,6 +2611,24 @@ int smblib_get_prop_batt_iterm(struct smb_charger *chg, return rc; } +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 +2655,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 +2688,133 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg, return rc; } +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; + bool user_vote_enable; + int i = 0; + int wireless_present = 0; + union power_supply_propval pval; + + pre_otg_switch = chg->otg_switch; + chg->otg_switch = enable; + + if (!chg->wls_psy) + chg->wls_psy = power_supply_get_by_name("wireless"); + if (chg->wls_psy) { + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_PRESENT, + &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get wireless present rc=%d\n", rc); + else + wireless_present = pval.intval; + } else { + smblib_err(chg, "Couldn't find wireless psy\n"); + } + + user_vote_enable = is_client_vote_enabled_locked(chg->otg_toggle_votable, USER_VOTER); + if ((chg->otg_switch == pre_otg_switch) && + !(user_vote_enable && wireless_present)) + return 0; + + pr_info("set otg_switch=%d\n", chg->otg_switch); + if (chg->otg_switch) { + if (wireless_present) + power_role = EN_DRP_MODE; + else + 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; + if ((power_role == EN_DRP_MODE) && ((ctrl & TYPEC_POWER_ROLE_CMD_MASK) == EN_DRP_MODE)) + break; + } + pr_info("retry time = %d,ctrl = %d\n", i, ctrl); + if (i == 10) + pr_err("retry time over\n"); + + if (power_role == EN_DRP_MODE) { + rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc); + } else { + rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, + 0); + if (rc < 0) + smblib_err(chg, "Couldn't clear exit state cfg 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 +2909,9 @@ int smblib_run_aicl(struct smb_charger *chg, int type) return rc; smblib_dbg(chg, PR_MISC, "re-running AICL\n"); + 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); @@ -2578,6 +3024,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg) "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc); return; } + smblib_err(chg, "QC_CHANGE_STATUS_REG=0x%02x", stat); smblib_hvdcp_set_fsw(chg, stat & QC_2P0_STATUS_MASK); vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0); @@ -3276,6 +3723,15 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } + 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 +3762,19 @@ 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; + if (chg->wireless_present) val->intval = 0; exit: @@ -3406,7 +3868,7 @@ static int smblib_estimate_adaptor_voltage(struct smb_charger *chg, val->intval = MICRO_5V; break; } - + val->intval = val->intval / 1000; return 0; } @@ -3429,7 +3891,8 @@ static int smblib_read_mid_voltage_chan(struct smb_charger *chg, * Figure out voltage from registers and calculations. */ if (val->intval < 1000000) - return smblib_estimate_adaptor_voltage(chg, val); + smblib_estimate_adaptor_voltage(chg, val); + val->intval = val->intval / 1000; return 0; } @@ -3447,6 +3910,7 @@ static int smblib_read_usbin_voltage_chan(struct smb_charger *chg, smblib_err(chg, "Couldn't read USBIN channel rc=%d\n", rc); return rc; } + val->intval = val->intval / 1000; return 0; } @@ -3487,6 +3951,11 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, goto restore_adc_config; } + if (!pval.intval) { + val->intval = 0; + goto unlock; + } + /* * Skip reading voltage only if USB is not present and we are not in * OTG mode. @@ -3507,7 +3976,8 @@ 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) + 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 +4049,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 +4069,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 +4168,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) switch (stat & DETECTED_SRC_TYPE_MASK) { case SNK_RP_STD_BIT: + case SNK_DAM_500MA_BIT: return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; case SNK_RP_1P5_BIT: return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM; @@ -3701,7 +4176,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 +4204,7 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) switch (stat & DETECTED_SNK_TYPE_MASK) { case AUDIO_ACCESS_RA_RA_BIT: + chg->is_audio_adapter = true; return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; case SRC_DEBUG_ACCESS_BIT: return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY; @@ -3757,10 +4232,14 @@ static int smblib_get_prop_typec_mode(struct smb_charger *chg) } smblib_dbg(chg, PR_REGISTER, "TYPE_C_MISC_STATUS_REG = 0x%02x\n", stat); - if (stat & SNK_SRC_MODE_BIT) - return smblib_get_prop_dfp_mode(chg); - else - return smblib_get_prop_ufp_mode(chg); + if (stat & SNK_SRC_MODE_BIT) { + rc = smblib_get_prop_dfp_mode(chg); + } else { + rc = smblib_get_prop_ufp_mode(chg); + } + pr_info("typec mode is %d\n", rc); + + return rc; } inline int smblib_get_usb_prop_typec_mode(struct smb_charger *chg, @@ -4212,19 +4691,28 @@ int smblib_get_prop_connector_health(struct smb_charger *chg) return POWER_SUPPLY_HEALTH_COOL; } +#define PD_PANELON_CURRENT_UA 3000000 +#define PD_PANELOFF_CURRENT_UA 3000000 +#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; + if (chg->oem_lcd_is_on) + rp_ua = PD_PANELON_CURRENT_UA; + else + rp_ua = TYPEC_HIGH_CURRENT_UA; break; case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: /* fall through */ default: - rp_ua = DCP_CURRENT_UA; + if (chg->oem_lcd_is_on) + rp_ua = DCP_CURRENT_UA; + else + rp_ua = DCP_PANELOFF_CURRENT_UA; } return rp_ua; @@ -4248,6 +4736,10 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, rc = -EPERM; } + 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 +4834,7 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg, union power_supply_propval pval; int rc = 0; + 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 +5000,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, smblib_err(chg, "power role %d not supported\n", val->intval); return -EINVAL; } + 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, @@ -4604,6 +5099,7 @@ 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 @@ -4619,6 +5115,14 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, 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 + && chg->typec_mode != POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) { + 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, @@ -4629,10 +5133,24 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, * It is guaranteed that pd_active is set prior to * pd_current_max */ - vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_100MA); +/* @bsp, 2019/09/20 Wireless Charge otg support */ + if (!chg->wireless_present) + vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_100MA); 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); + + /* @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 +5164,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, dev_err(chg->dev, "Couldn't enable secondary charger rc=%d\n", rc); } + + 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 +5637,18 @@ irqreturn_t chg_state_change_irq_handler(int irq, void *data) } stat = stat & BATTERY_CHARGER_STATUS_MASK; + if (stat == TERMINATE_CHARGE) { + 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 +5699,11 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) int rc; u8 stat = 0, max_pulses = 0; + 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 +5774,7 @@ unsuspend_input: wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); + 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 +5828,39 @@ unsuspend_input: return IRQ_HANDLED; } +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 +6035,15 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; + 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 +6051,39 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) } vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + 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); + if (gpio_is_valid(chg->vbus_ctrl)) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(200)); + if (chg->wireless_present) { + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + if (chg->pd_active) + vote(chg->usb_icl_votable, PD_VOTER, false, 0); + } } else { if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; @@ -5493,6 +6102,16 @@ 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); + if (!chg->wireless_present) { + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + } else { + if ((chg->sink_src_mode == SRC_MODE) && !chg->is_audio_adapter) + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); + } + if (last_vbus_present != chg->vbus_present) + op_handle_usb_removal(chg); } power_supply_changed(chg->usb_psy); @@ -5509,6 +6128,16 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; + 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); @@ -5516,16 +6145,68 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); - smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_5V : - chg->chg_freq.freq_removal); + if (chg->wireless_present) { + if (chg->wireless_high_vol_mode) + smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_12V : + chg->chg_freq.freq_removal); + else + smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_6V_8V : + chg->chg_freq.freq_removal); + } else { + smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_5V : + chg->chg_freq.freq_removal); + } + 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); - rc = smblib_request_dpdm(chg, true); - if (rc < 0) - smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + if (!chg->wireless_present) { + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + } else { + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + if (chg->pd_active) + vote(chg->usb_icl_votable, PD_VOTER, false, 0); + } + + 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)); + if (chg->check_slow_charge) + schedule_delayed_work( + &chg->slow_chg_check_work, + msecs_to_jiffies(chg->probe_done ? 400 : 10000)); + schedule_delayed_work(&chg->op_check_ffc_work, + msecs_to_jiffies(TIME_1000MS)); /* Enable SW Thermal regulation */ rc = smblib_set_sw_thermal_regulation(chg, true); if (rc < 0) @@ -5592,10 +6273,16 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) false, 0); } - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); - + if (!chg->wireless_present) { + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + } else { + if ((chg->sink_src_mode == SRC_MODE) && !chg->is_audio_adapter) + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); + } + if (last_vbus_present != chg->vbus_present) + op_handle_usb_removal(chg); smblib_update_usb_type(chg); } @@ -5608,6 +6295,19 @@ 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"); + 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) @@ -5615,6 +6315,8 @@ 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 +6325,14 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) return IRQ_HANDLED; } +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) { @@ -5710,6 +6420,15 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, } } + if (chg->wireless_present) { + vote(chg->limited_irq_disable_votable, CHARGER_TYPE_VOTER, + false, 0); + vote(chg->hdc_irq_disable_votable, CHARGER_TYPE_VOTER, false, + 0); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); + } + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, rising ? "rising" : "falling"); } @@ -5751,6 +6470,11 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) return; } + if (chg->wireless_present) { + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 1500000); + return; + } + /* rp-std or legacy, USB BC 1.2 */ switch (pst) { case POWER_SUPPLY_TYPE_USB: @@ -5758,13 +6482,8 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) * USB_PSY will vote to increase the current to 500/900mA once * enumeration is done. */ - if (!is_client_vote_enabled(chg->usb_icl_votable, - USB_PSY_VOTER)) { - /* if flash is active force 500mA */ - vote(chg->usb_icl_votable, USB_PSY_VOTER, true, - is_flash_active(chg) ? - SDP_CURRENT_UA : SDP_100_MA); - } + if (!is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 500000); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); break; case POWER_SUPPLY_TYPE_USB_CDP: @@ -5781,12 +6500,12 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) * if this is a SDP and appropriately set the current */ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_100_MA); + 1500000); break; case POWER_SUPPLY_TYPE_UNKNOWN: default: vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_100_MA); + SDP_CURRENT_UA); break; } } @@ -5794,6 +6513,7 @@ 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; + int temp_region = 0, current_limit_ua = 0; if (!rising) return; @@ -5816,6 +6536,65 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) break; } + 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; + + if (chg->wireless_present) + current_limit_ua = DEFAULT_DCP_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 (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 +6606,12 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) int rc = 0; u8 stat; + 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 +6621,8 @@ 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; } + 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 +6771,8 @@ static void typec_src_fault_condition_cfg(struct smb_charger *chg, bool src) static void typec_sink_insertion(struct smb_charger *chg) { int rc; - + if (!chg->is_audio_adapter && !chg->wireless_present) + 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 +6965,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 +6977,7 @@ static void typec_sink_removal(struct smb_charger *chg) smblib_notify_usb_host(chg, false); chg->otg_present = false; } + chg->is_audio_adapter = false; } static void typec_src_removal(struct smb_charger *chg) @@ -6226,12 +7016,12 @@ 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); + 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 +7231,44 @@ out: return IRQ_HANDLED; } +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; + int rc; + int wireless_present = 0; + union power_supply_propval pval; + 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, @@ -6453,11 +7276,32 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } + if (!chg->wls_psy) + chg->wls_psy = power_supply_get_by_name("wireless"); + if (chg->wls_psy) { + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_PRESENT, + &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get wireless present rc=%d\n", rc); + else + wireless_present = pval.intval; + } else { + smblib_err(chg, "Couldn't find wireless psy\n"); + } + typec_mode = smblib_get_prop_typec_mode(chg); if (chg->sink_src_mode != UNATTACHED_MODE && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; + if (wireless_present) { + rc = smblib_masked_write(g_chg, TYPE_C_EXIT_STATE_CFG_REG, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, + 0); + if (rc < 0) + smblib_err(g_chg, "Couldn't set exit state cfg rc=%d\n", rc); + } smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); @@ -6493,6 +7337,12 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) 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; + } + 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", @@ -6767,6 +7617,11 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) int rc, wireless_vout = 0, wls_set = 0; int sec_charger; + if (chg->wireless_present) { + pr_info("Do not use the following process when wireless charging\n"); + return IRQ_HANDLED; + } + rc = smblib_get_prop_vph_voltage_now(chg, &pval); if (rc < 0) return IRQ_HANDLED; @@ -6917,9 +7772,16 @@ 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; + 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 +7801,16 @@ 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)); - } + 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; @@ -7000,6 +7846,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,6 +7883,3630 @@ irqreturn_t temp_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } +/* @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, + get_aicl_work); + int rc, settled_ua; + + 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); +} + +/* @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 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; + + if (!chg->vbus_present) + return; + + chg->connecter_temp = get_usb_temp(chg); + batt_temp = get_prop_batt_temp(chg)/10; + interval_temp = chg->connecter_temp - batt_temp; + + /* 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; + + 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_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; + if ((chg->current_temp - + chg->pre_temp) >= + chg->third_protect_rise_rate) { /* 3 degree per 1.5 senconds*/ + chg->connector_short = true; + pr_info("cout_run=%d,short=%d\n", + chg->count_run, + chg->connector_short); + op_disconnect_vbus(chg, true); + return; + } + } + + chg->count_run++;/*count ++*/ + + 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 CONNECTER_RECOVERY_CHECK_INTERVAL 3000 //ms +static void op_connecter_recovery_charge_work(struct work_struct *work) +{ + 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; + + if (!chg->disconnect_vbus) + return; + + 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, connecter_temp=%d, interval_temp=%d", + chg->disconnect_vbus, chg->hw_detect, 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; + } + + schedule_delayed_work(&chg->connecter_recovery_work, + msecs_to_jiffies(CONNECTER_RECOVERY_CHECK_INTERVAL)); +} + +/* @bsp, 2019/12/20 add pd skin thermal check */ +#define PD_CALLON_CURRENT_UA 1800000 +#define PD_SKIN_THERMAL_CURRENT_UA 2000000 +#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; + int ua, icl; + + if (!chg->pd_active) + return; + + is_call_on = check_call_on_status(); + is_skin_temp_high = check_skin_thermal_high(); + if (is_call_on) + ua = PD_CALLON_CURRENT_UA; + else if (is_skin_temp_high) + ua = PD_SKIN_THERMAL_CURRENT_UA; + else + ua = PD_PANELOFF_CURRENT_UA; + + icl = get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER); + if (ua != icl) { + pr_info("PD: skin_thermal_temp=(%d), is_skin_thermal_high(%d), ua(%d)\n", + chg->skin_thermal_temp, chg->is_skin_thermal_high, ua); + vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, ua); + } + + schedule_delayed_work(&chg->pd_current_check_work, + msecs_to_jiffies(PD_CHECK_INTERVAL_PERIOD)); +} + +irqreturn_t smblib_handle_aicl_done(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + 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; +} + +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); + if (g_chg->wireless_present) { + vote(g_chg->usb_icl_votable, WLCH_FFC_VOTER, true, 1000000); + vote(g_chg->fcc_votable, DEFAULT_VOTER, true, 1500 * 1000); + } else { + vote(g_chg->fcc_votable, DEFAULT_VOTER, true, 1000 * 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->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->apsd_not_done = false; + chg->slow_charger = false; + chg->slow_chg_count = 0; + 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->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; + 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); +} + +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 (chg->wireless_present) { + pr_info("wireless charge, don't set usb switch\n"); + return; + } + + if (enable) { + pr_err("switch on fastchg\n"); + chg->switch_on_fastchg = 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_en_gpio_value(1); + 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; + 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); + return; + } + if (!is_usb_present(chg)) { + mutex_unlock(&chg->sw_dash_lock); + 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); + } + 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->pd_active) { + chg->ck_dash_count = 0; + pr_info("pd_active return retrigger_dash\n"); + 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); + chg->ck_dash_count = 0; + } else { + chg->ck_dash_count++; + schedule_delayed_work(&chg->rechk_sw_dsh_work, + msecs_to_jiffies(TIME_200MS)); + } +} + +static void op_check_slow_charge_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + slow_chg_check_work.work); + union power_supply_propval vbus_val; + int rc, ibat, temp_region, soc; + int suspend; + const struct apsd_result *apsd_result; + + pr_info("chg->slow_chg_count=%d\n", chg->slow_chg_count); + soc = get_prop_batt_capacity(chg); + if (chg->wireless_present + || chg->usb_enum_status + || soc > 80 + || chg->chg_done + || chg->chg_disabled + || chg->dash_present) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + return; + } + temp_region = op_battery_temp_region_get(chg); + if (temp_region == BATT_TEMP_COLD + && temp_region == BATT_TEMP_HOT + && temp_region == BATT_TEMP_LITTLE_COLD) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + return; + } + apsd_result = smblib_update_usb_type(chg); + if (apsd_result->bit == SDP_CHARGER_BIT + || apsd_result->bit == CDP_CHARGER_BIT) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + return; + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + 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->slow_chg_count = 0; + chg->slow_charger = false; + return; + } + rc = smblib_get_usb_suspend(chg, &suspend); + if (rc < 0) { + pr_info("%s,Couldn't get usb suspend rc=%d\n", __func__, rc); + return; + } + if (suspend) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + pr_info("usb suspend, return\n"); + return; + } + ibat = get_prop_batt_current_now(chg); + if (-ibat > USBIN_500MA) { + chg->slow_chg_count = 0; + chg->slow_charger = false; + pr_info("ibat is %d\n", ibat); + return; + } + if (chg->slow_chg_count >= SLOW_CHG_CHECK_COUTNT) { + pr_info("slow charge detected\n"); + chg->slow_chg_count = 0; + chg->slow_charger = true; + power_supply_changed(chg->batt_psy); + } else { + chg->slow_chg_count++; + schedule_delayed_work(&chg->slow_chg_check_work, + msecs_to_jiffies(400)); + } +} + +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->wireless_present + || 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->pd_active) { + chg->ck_apsd_count = 0; + pr_info("pd_active return\n"); + return; + } + if (chg->wireless_present || !chg->check_slow_charge) { + chg->ck_apsd_count = 0; + return; + } + if (chg->usb_enum_status || (apsd_result->bit && chg->typec_mode)) { + 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->typec_mode) { + 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); + chg->apsd_not_done = true; + if (!apsd_result->bit) + op_rerun_apsd(chg); + } else { + chg->ck_apsd_count++; + schedule_delayed_work(&chg->op_check_apsd_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +static void check_ffc_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + op_check_ffc_work.work); + union power_supply_propval vbus_val; + int rc, temp_region, soc; + int suspend; + const struct apsd_result *apsd_result; + + pr_info("chg->ffc_check_count=%d\n", chg->ffc_check_count); + soc = get_prop_batt_capacity(chg); + if (chg->wireless_present + || chg->usb_enum_status + || soc <= 85 + || soc == 100 + || chg->chg_done + || chg->chg_disabled + || op_get_fastchg_ing(chg) + || (chg->ffc_status != FFC_DEFAULT)) { + chg->ffc_check_count = 0; + return; + } + temp_region = op_battery_temp_region_get(chg); + if (temp_region == BATT_TEMP_COLD + && temp_region == BATT_TEMP_HOT + && temp_region == BATT_TEMP_LITTLE_COLD) { + chg->ffc_check_count = 0; + return; + } + apsd_result = smblib_update_usb_type(chg); + if (apsd_result->bit == SDP_CHARGER_BIT + || apsd_result->bit == CDP_CHARGER_BIT) { + chg->ffc_check_count = 0; + return; + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + chg->ffc_check_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->ffc_check_count = 0; + return; + } + rc = smblib_get_usb_suspend(chg, &suspend); + if (rc < 0) { + pr_info("%s,Couldn't get usb suspend rc=%d\n", __func__, rc); + return; + } + if (suspend) { + chg->ffc_check_count = 0; + pr_info("usb suspend, return\n"); + return; + } + if (soc >= FFC_START_CAPACITY + && (chg->ffc_status == FFC_DEFAULT) + && (chg->ffc_check_count > 6) + && chg->dash_present) { + pr_info("normal chg ffc start\n"); + chg->ffc_check_count = 0; + op_switch_normal_set(); + } else { + chg->ffc_check_count++; + schedule_delayed_work(&chg->op_check_ffc_work, + msecs_to_jiffies(400)); + } +} + + +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; +/* @bsp, 2019/08/30 Wireless Charging porting */ + if (chg->wireless_present) + return; + if (chg->apsd_delayed) + 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); + g_chg->slow_chg_count = 0; + g_chg->slow_charger = false; + g_chg->apsd_not_done = false; + } + 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; + } + if (-ua > USBIN_500MA) + chg->slow_charger = false; + 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, }; + bool wlchg_disable_batt_charge = false; + bool wlchg_online = false; + + if (!chg->wls_psy) + chg->wls_psy = power_supply_get_by_name("wireless"); + if (chg->wls_psy) { + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, + &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get wlchg batt status rc=%d\n", rc); + else + wlchg_disable_batt_charge = pval.intval; + pval.intval = 0; + + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_ONLINE, + &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get wlchg online status rc=%d\n", rc); + else + wlchg_online = pval.intval; + pval.intval = 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; + if ((chg->wireless_present || wlchg_online) && !wlchg_disable_batt_charge) + 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->wireless_present && + temp_region != BATT_TEMP_COLD && + temp_region != BATT_TEMP_LITTLE_COLD && + temp_region != BATT_TEMP_HOT) { + vote(chg->fcc_votable, DEFAULT_VOTER, false, 0); + } else if (chg->pd_active && ( + temp_region == BATT_TEMP_NORMAL + || temp_region == BATT_TEMP_PRE_NORMAL + || temp_region == BATT_TEMP_LITTLE_COOL)) { + vote(chg->fcc_votable, + DEFAULT_VOTER, true, PD_PANELOFF_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 < 22C */ +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; +} + +/* 15C < 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->usb_enum_status = false; + chg->non_std_chg_present = false; + chg->is_audio_adapter = false; + chg->init_irq_done = false; +/* @bsp, 2019/08/30 Wireless Charging porting */ + chg->wireless_present = false; + chg->apsd_delayed = false; + chg->apsd_not_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; + +/* @bsp, 2019/08/30 Wireless Charging porting */ + if (chg->wireless_present) + return; + + pr_err("charger_voltage=%d charger_ovp=%d\n", vchg_mv, chg->chg_ovp); + + 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_300MV); + 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; + int usbin_curr = 0; + int usbin_curr_max = 0; + union power_supply_propval pval = {0, }; + int rc; + + 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; + if (g_chg->wireless_present) + vote(g_chg->usb_icl_votable, + WLCH_FFC_VOTER, true, 800000); + 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; + if (g_chg->wireless_present) + vote(g_chg->usb_icl_votable, + WLCH_FFC_VOTER, true, 800000); + 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->wireless_present) { + rc = smblib_get_prop_usb_current_now(chg, &pval); + if (rc < 0) { + pr_err("get usb input current error, rc=%d\r\n", rc); + usbin_curr = 0; + } else { + usbin_curr = pval.intval / 1000; + } + usbin_curr_max = get_effective_result(chg->usb_icl_votable); + if (usbin_curr_max < 0) + usbin_curr_max = 0; + else + usbin_curr_max = usbin_curr_max / 1000; + } + } + + 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; + if (g_chg->wireless_present) + vote(g_chg->usb_icl_votable, + WLCH_FFC_VOTER, true, 800000); + 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; + if (g_chg->wireless_present) + vote(g_chg->usb_icl_votable, + WLCH_FFC_VOTER, true, 800000); + 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) { + if (chg->wireless_present && (usbin_curr != 0) && + (usbin_curr_max != 0)) { + if (usbin_curr > usbin_curr_max - 100) + chg->ffc_count = 0; + else + chg->ffc_count++; + } else { + 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) { + if (chg->wireless_present && (usbin_curr != 0) && + (usbin_curr_max != 0)) { + if (usbin_curr > usbin_curr_max - 100) + chg->ffc_count = 0; + else + chg->ffc_count++; + } else { + 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("[BATTERY] Battery full by sw when icharging>=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; + } + +/* @bsp, 2019/08/30 Wireless Charging porting */ + if (chg->wireless_present) { + pr_info("chk_non_std_chger,wireless_present\n"); + chg->non_stand_chg_count = 0; + return; + } + if (chg->apsd_delayed) { + pr_info("chk_non_std_chger,apsd_delayed\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); + } + } +} + +#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; + + 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; + } + + if (chg->skin_thermal_temp >= chg->skin_thermal_medium_threshold)//38 + chg->is_skin_thermal_medium = true; + else if (chg->skin_thermal_temp < chg->skin_thermal_normal_threshold)//36 + chg->is_skin_thermal_medium = false; + + if (chg->skin_thermal_temp >= chg->skin_thermal_high_threshold)//41 + chg->is_skin_thermal_high = true; + else if (chg->skin_thermal_temp < chg->skin_thermal_pre_high_threshold)//39 + chg->is_skin_thermal_high = false; + + if (chg->pd_active && + chg->skin_thermal_temp >= chg->pd_skin_thermal_high_threshold) + chg->is_skin_thermal_high = true; + else if (chg->pd_active && + chg->skin_thermal_temp < chg->pd_skin_thermal_normal_threshold) + chg->is_skin_thermal_high = false; + + pr_info("skin_thermal_temp=(%d), is_skin_thermal_medium(%d), is_skin_thermal_high(%d), pd_active(%d)\n", + chg->skin_thermal_temp, + chg->is_skin_thermal_medium, + chg->is_skin_thermal_high, chg->pd_active); + + 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_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; + + 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; + + if (is_call_on == 1) { + pr_info("is_call_on=(%d)\n", + is_call_on); + return true; + } + + pr_info("is_call_on=(%d)\n", + is_call_on); + return false; +} + +/* @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)); +} + +int plugin_update(struct smb_charger *chg) +{ + int rc = 0; + char *connected_str[2] = { "USBCable=CONNECTED", NULL}; + char *disconnected_str[2] = { "USBCable=DISCONNECTED", NULL}; + + rc = kobject_uevent_env(&chg->dev->kobj, KOBJ_CHANGE, + chg->hw_detect ? connected_str : disconnected_str); + + return rc; +} + +/*usb connector hw auto detection*/ +static void op_otg_switch(struct work_struct *work) +{ + bool usb_pluged; + bool user_vote_enable; + int wireless_present = 0; + union power_supply_propval pval; + int rc; + + if (!g_chg) + return; + + if (!g_chg->wls_psy) + g_chg->wls_psy = power_supply_get_by_name("wireless"); + if (g_chg->wls_psy) { + rc = power_supply_get_property(g_chg->wls_psy, + POWER_SUPPLY_PROP_PRESENT, + &pval); + if (rc < 0) + smblib_err(g_chg, "Couldn't get wireless present rc=%d\n", rc); + else + wireless_present = pval.intval; + } else { + smblib_err(g_chg, "Couldn't find wireless psy\n"); + } + + user_vote_enable = is_client_vote_enabled(g_chg->otg_toggle_votable, USER_VOTER); + usb_pluged = gpio_get_value(g_chg->plug_irq) ? false : true; + if (usb_pluged == g_chg->pre_cable_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); + if (user_vote_enable && wireless_present) + rerun_election(g_chg->otg_toggle_votable); + } else { + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 0, 0); + } + return; + } + + if (usb_pluged) { + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + if (user_vote_enable && wireless_present) + rerun_election(g_chg->otg_toggle_votable); + 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)); + } + rc = plugin_update(g_chg); + pr_info("%s:hw_detect=%d and report rc: %d\n", + __func__, g_chg->hw_detect, rc); + g_chg->pre_cable_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, }; + union power_supply_propval pval = {0, }; + int vbatdet_mv; + 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 + if (chg->wireless_present && !chg->wls_psy) + chg->wls_psy = power_supply_get_by_name("wireless"); + +#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); + + if (chg->wlchg_fast) + goto out; + + 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->wireless_present) { + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_VBATDET, + &pval); + if (rc < 0) { + pr_err("can't get wireless charge vbatdet\n"); + vbatdet_mv = 0; + } else { + vbatdet_mv = pval.intval; + } + } else { + if (temp_region > BATT_TEMP_COLD && temp_region < BATT_TEMP_HOT) + vbatdet_mv = chg->vbatdet[temp_region]; + else + vbatdet_mv = 0; + } + if (!chg->chg_ovp && chg->chg_done + && temp_region > BATT_TEMP_COLD + && temp_region < BATT_TEMP_HOT + && vbatdet_mv >= 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 if (chg->apsd_not_done || chg->slow_charger) + return PROTECT_INVALID_CHARGER; + 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, @@ -7154,6 +11627,9 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, return rc; } + if (!chg->hw_detect) + return 0; + /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); @@ -7294,6 +11770,32 @@ static void pl_update_work(struct work_struct *work) POWER_SUPPLY_CP_NONE, false); } +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!"); + } + } +#endif /*CONFIG_FB*/ +} + static void clear_hdc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -7954,6 +12456,14 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + 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, chg); @@ -8019,6 +12529,8 @@ static void smblib_destroy_votables(struct smb_charger *chg) { if (chg->dc_suspend_votable) destroy_votable(chg->dc_suspend_votable); + 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 +12547,8 @@ 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); + 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 +12571,60 @@ int smblib_init(struct smb_charger *chg) mutex_init(&chg->smb_lock); mutex_init(&chg->irq_status_lock); mutex_init(&chg->dcin_aicl_lock); + + 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); + + 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->op_check_ffc_work, check_ffc_work); + INIT_DELAYED_WORK(&chg->slow_chg_check_work, op_check_slow_charge_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); + 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); + 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); @@ -8088,6 +12646,7 @@ int smblib_init(struct smb_charger *chg) 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 +12660,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 { @@ -8126,6 +12686,7 @@ int smblib_init(struct smb_charger *chg) chg->cp_reason = POWER_SUPPLY_CP_NONE; chg->thermal_status = TEMP_BELOW_RANGE; chg->typec_irq_en = true; + chg->chg_wake_lock_on = false; chg->cp_topo = -EINVAL; chg->dr_mode = TYPEC_PORT_DRP; @@ -8233,6 +12794,9 @@ 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); + + 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,7 +12812,7 @@ int smblib_deinit(struct smb_charger *chg) smblib_err(chg, "Unsupported mode %d\n", chg->mode); return -EINVAL; } - + notify_dash_unplug_unregister(¬ify_unplug_event); smblib_iio_deinit(chg); return 0; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 8ee11fb3a3b2..f59a40c4bbe3 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -16,6 +16,7 @@ #include #include #include "storm-watch.h" +#include #include "battery.h" enum print_reason { @@ -25,8 +26,46 @@ enum print_reason { PR_PARALLEL = BIT(3), PR_OTG = BIT(4), PR_WLS = BIT(5), + PR_OP_DEBUG = BIT(6), + PR_FAST_DEBUG = BIT(7), }; +#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 SLOW_CHG_CHECK_COUTNT 8 +#define FFC_START_CAPACITY 95 + +#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 SKIM_THERMAL_MEDIUM 38 +#define SKIN_THERMAL_NORMAL 36 +#define FULL_COUNT_SW_NUM 1 + +#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" @@ -77,14 +116,20 @@ enum print_reason { #define CC_MODE_VOTER "CC_MODE_VOTER" #define MAIN_FCC_VOTER "MAIN_FCC_VOTER" #define DCIN_AICL_VOTER "DCIN_AICL_VOTER" +#define WIRED_CONN_VOTER "WIRED_CONN_VOTER" #define WLS_PL_CHARGING_VOTER "WLS_PL_CHARGING_VOTER" #define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" #define OVERHEAT_LIMIT_VOTER "OVERHEAT_LIMIT_VOTER" #define TYPEC_SWAP_VOTER "TYPEC_SWAP_VOTER" +#define WLCH_FFC_VOTER "WLCH_FFC_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 @@ -295,6 +340,7 @@ enum icl_override_mode { SW_OVERRIDE_USB51_MODE, /* ICL other than USB51 */ SW_OVERRIDE_HC_MODE, + SW_OVERRIDE_WIRELESS_MODE, }; /* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */ @@ -346,6 +392,7 @@ struct smb_params { struct smb_chg_param icl_max_stat; struct smb_chg_param icl_stat; struct smb_chg_param otg_cl; + struct smb_chg_param otg_vol; struct smb_chg_param dc_icl; struct smb_chg_param jeita_cc_comp_hot; struct smb_chg_param jeita_cc_comp_cold; @@ -365,6 +412,9 @@ struct smb_iio { struct iio_channel *mid_chan; struct iio_channel *batt_i_chan; struct iio_channel *connector_temp_chan; + 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,6 +431,10 @@ 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; enum smb_mode mode; struct smb_chg_freq chg_freq; int otg_delay_ms; @@ -393,6 +447,13 @@ struct smb_charger { struct mutex ps_change_lock; struct mutex irq_status_lock; struct mutex dcin_aicl_lock; + + struct mutex write_lock; + struct mutex sw_dash_lock; + struct pinctrl_state *ship_mode_default; + struct pinctrl_state *usb_temperature_default; + struct pinctrl_state *usb_temperature_sec; + struct pinctrl *pinctrl; spinlock_t typec_pr_lock; struct mutex adc_lock; struct mutex dpdm_lock; @@ -403,6 +464,7 @@ struct smb_charger { struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *bms_psy; + 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 +473,11 @@ struct smb_charger { /* notifiers */ struct notifier_block nb; +#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 +499,7 @@ struct smb_charger { /* votables */ struct votable *dc_suspend_votable; + struct votable *otg_toggle_votable; struct votable *fcc_votable; struct votable *fcc_main_votable; struct votable *fv_votable; @@ -458,6 +526,28 @@ struct smb_charger { struct work_struct dcin_aicl_work; struct work_struct cp_status_change_work; struct delayed_work ps_change_timeout_work; + 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 delayed_work op_check_ffc_work; + + struct delayed_work slow_chg_check_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 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 +590,118 @@ struct smb_charger { bool typec_role_swap_failed; /* cached status */ + 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 slow_chg_count; + int ffc_check_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; + int pre_cable_pluged; + bool apsd_not_done; + bool slow_charger; + bool check_slow_charge; + 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 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; + 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; + int skin_thermal_high_threshold; + int skin_thermal_pre_high_threshold; + int skin_thermal_medium_threshold; + int skin_thermal_normal_threshold; + bool enable_dash_current_adjust; + int pd_skin_thermal_high_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 +721,34 @@ struct smb_charger { bool fake_chg_status_on_debug_batt; int default_icl_ua; int otg_cl_ua; + + int sw_iterm_ma; + int little_cold_iterm_ma; + bool check_batt_full_by_sw; + bool OTG_ICL_CTRL; + int OTG_LOW_BAT; + int OTG_LOW_BAT_ICL; + int OTG_NORMAL_BAT_ICL; + 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_medium; + int disconnect_vbus; + int vbus_ctrl; + bool low_voltage_charger; + bool vph_sel_disable; + bool vph_set_flag; + bool uusb_apsd_rerun_done; bool typec_present; int fake_input_current_limited; @@ -615,8 +845,55 @@ struct smb_charger { int dcin_uv_count; ktime_t dcin_uv_last_time; int last_wls_vout; + bool wireless_present; + bool apsd_delayed; + bool wireless_high_vol_mode; + bool chg_wake_lock_on; + bool wlchg_fast; }; +int smblib_set_prop_charge_parameter_set(struct smb_charger *chg); +extern void set_mcu_en_gpio_value(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 void notify_pd_in_to_wireless(void); +extern struct smb_charger *g_chg; +extern struct drm_panel *lcd_active_panel; + +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); +int op_charging_en(struct smb_charger *chg, bool en); +int op_wireless_high_vol_en(bool enable); + +bool get_prop_fastchg_is_ok(struct smb_charger *chg); +void op_disconnect_vbus(struct smb_charger *chg, bool enable); +int plugin_update(struct smb_charger *chg); + 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 +975,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, @@ -839,4 +1118,6 @@ int smblib_get_qc3_main_icl_offset(struct smb_charger *chg, int *offset_ua); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); +extern void exchg_information_register(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 311e810c31c0..90420443f8bf 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -28,6 +28,10 @@ * CHGR Peripheral Registers * ********************************/ #define BATTERY_CHARGER_STATUS_1_REG (CHGR_BASE + 0x06) +#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, @@ -143,6 +147,8 @@ enum { #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) #define OTG_EN_BIT BIT(0) +#define DCDC_VBOOST_CFG (DCDC_BASE + 0x86) + #define DCDC_FSW_SEL_REG (DCDC_BASE + 0x50) #define DCDC_OTG_CURRENT_LIMIT_CFG_REG (DCDC_BASE + 0x52) @@ -150,6 +156,11 @@ enum { #define DCDC_OTG_CFG_REG (DCDC_BASE + 0x53) #define OTG_EN_SRC_CFG_BIT BIT(1) +#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) @@ -260,6 +271,11 @@ enum { #define FORCE_5V BIT(0) #define FORCE_NULL 0 +#define USBIN_ADAPTER_ALLOW_OVERRIDE_REG (USBIN_BASE + 0x44) +#define USBIN_ADAPTER_CONTINUOUS_BIT BIT(3) +#define USBIN_ADAPTER_FORCE_9V_BIT BIT(1) +#define USBIN_ADAPTER_FORCE_5V_BIT BIT(0) + #define USB_CMD_PULLDOWN_REG (USBIN_BASE + 0x45) #define EN_PULLDOWN_USB_IN_BIT BIT(0) @@ -275,6 +291,19 @@ enum { HVDCP_PULSE_COUNT_MAX_QC2_INVALID = 0xC0 }; +#define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60) +enum { + USBIN_ADAPTER_ALLOW_5V = 0, + USBIN_ADAPTER_ALLOW_9V = 2, + USBIN_ADAPTER_ALLOW_5V_OR_9V = 3, + USBIN_ADAPTER_ALLOW_12V = 4, + USBIN_ADAPTER_ALLOW_5V_OR_12V = 5, + USBIN_ADAPTER_ALLOW_9V_TO_12V = 6, + USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7, + USBIN_ADAPTER_ALLOW_5V_TO_9V = 8, + USBIN_ADAPTER_ALLOW_5V_TO_12V = 12, +}; + #define USBIN_OPTIONS_1_CFG_REG (USBIN_BASE + 0x62) #define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6) #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5) @@ -304,6 +333,19 @@ 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) +#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) @@ -356,6 +398,8 @@ enum { #define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09) #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) +#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 +424,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) +#define EN_DRP_MODE 0 +#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 a2e9bf95918a..4f272089babe 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -403,7 +403,7 @@ reschedule: } -static int get_val(struct range_data *range, int hysteresis, int current_index, +int get_val(struct range_data *range, int hysteresis, int current_index, int threshold, int *new_index, int *val) { diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h index 285528f6af94..b82a483fead2 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.h +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -27,4 +27,7 @@ void qcom_step_chg_deinit(void); int read_range_data_from_node(struct device_node *node, const char *prop_str, struct range_data *ranges, int max_threshold, u32 max_value); +int get_val(struct range_data *range, int hysteresis, int current_index, + int threshold, + int *new_index, int *val); #endif /* __STEP_CHG_H__ */ diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index b5832161e81f..782dace0b640 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1996,6 +1996,18 @@ 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"}, + {"slpi", "glink-slpi"}, + {"modem", "glink-modem"}, + {"npu", "glink-npu"}, +}; + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -2007,6 +2019,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) @@ -2071,6 +2085,20 @@ 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 40fefd9c38b1..3b0921e46e1a 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 @@ -216,7 +218,12 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) 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,6 +235,8 @@ 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); @@ -235,6 +244,20 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 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 +282,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 f1aae8beff9e..cfe6af9821fe 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -132,6 +132,48 @@ config SCSI_UFS_HISI Select this if you have UFS controller on Hisilicon chipset. If unsure, say N. +config UFSFEATURE + bool "UFS feature activate" + default y + depends on SCSI_UFSHCD + help + UFS feature activate such as hpb, tw and etc. + +config UFSHPB + bool "UFS Host Performance Booster support" + default y + depends on SCSI_UFSHCD && UFSFEATURE + help + UFS HPB Feature Enable + +config HPB_ERR_INJECTION + bool "HPB ERROR INJECTION" + depends on SCSI_UFSHCD && UFSFEATURE && UFSHPB + help + error injection for checking HPB entry integrity + +config UFSTW + bool "UFS Turbo Write support" + default y + depends on SCSI_UFSHCD && UFSFEATURE + help + UFS TW Feature Enable + +config UFSTW_IGNORE_GUARANTEE_BIT + bool "Ignore UFS Turbo Write Life Time Guarantee bit for POC" + default y + depends on SCSI_UFSHCD && UFSFEATURE && UFSTW + help + ignore the guarantee bit[31] of dTurboWriteBufferLifeTimeEst for PoC + +config UFSTW_BOOT_ENABLED + bool "Turbo Write enabled at boot time" + default y + depends on SCSI_UFSHCD && UFSFEATURE && UFSTW + help + fTurboWriteEn and fTurboWriteBufferFlushDuringHibnerEnter flags + are enabled at boot time. + config SCSI_UFS_CRYPTO bool "UFS Crypto Engine Support" depends on SCSI_UFSHCD && BLK_INLINE_ENCRYPTION diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index e7294e6f42a3..60632367b090 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -13,3 +13,13 @@ obj-$(CONFIG_DEBUG_FS) += ufs-debugfs.o ufs-qcom-debugfs.o obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO_QTI) += ufshcd-crypto-qti.o +# filter instantnoodle, instantnoodlep ... +ifeq ($(filter instantnoodle%, $(OEM_TARGET_PRODUCT)),) +obj-$(CONFIG_UFSFEATURE) += ufs31/ufsfeature.o +obj-$(CONFIG_UFSHPB) += ufs31/ufshpb.o +obj-$(CONFIG_UFSTW) += ufs31/ufstw.o +else +obj-$(CONFIG_UFSFEATURE) += ufs30/ufsfeature.o +obj-$(CONFIG_UFSHPB) += ufs30/ufshpb.o +obj-$(CONFIG_UFSTW) += ufs30/ufstw.o +endif diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index cededde98be3..3e2a9da4f8ff 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -137,11 +137,11 @@ enum desc_header_offset { }; enum ufs_desc_def_size { - QUERY_DESC_DEVICE_DEF_SIZE = 0x59, - QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, - QUERY_DESC_UNIT_DEF_SIZE = 0x23, + QUERY_DESC_DEVICE_DEF_SIZE = 0x5F, + QUERY_DESC_CONFIGURATION_DEF_SIZE = 0xE6, + QUERY_DESC_UNIT_DEF_SIZE = 0x2D, QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, - QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48, + QUERY_DESC_GEOMETRY_DEF_SIZE = 0x59, QUERY_DESC_POWER_DEF_SIZE = 0x62, QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; @@ -166,6 +166,18 @@ 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) +#if defined(UFS3V1) + UNIT_DESC_TW_LU_WRITE_BUFFER_ALLOC_UNIT = 0x29, +#elif defined(UFS3V0) + UNIT_DESC_TW_LU_MAX_BUF_SIZE = 0x29, +#endif +#endif }; /* Device descriptor parameters offsets in bytes*/ @@ -209,6 +221,29 @@ enum device_desc_param { DEVICE_DESC_PARAM_WB_US_RED_EN = 0x53, DEVICE_DESC_PARAM_WB_TYPE = 0x54, DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS = 0x55, + DEVICE_DESC_PARAM_FEAT_SUP = 0x1F, +#if defined(CONFIG_UFSHPB) + DEVICE_DESC_PARAM_HPB_VER = 0x40, +#if defined(UFS3V1) + DEVICE_DESC_PARAM_HPB_CONTROL = 0x42, +#endif +#endif +#if defined(CONFIG_UFSFEATURE) + DEVICE_DESC_PARAM_EX_FEAT_SUP = 0x4F, +#endif +#if defined(CONFIG_UFSTW) +#if defined(UFS3V1) + DEVICE_DESC_PARAM_TW_VER = 0x4D, +#endif + DEVICE_DESC_PARAM_TW_RETURN_TO_USER = 0x53, + DEVICE_DESC_PARAM_TW_BUF_TYPE = 0x54, +#if defined(UFS3V1) + DEVICE_DESC_PARAM_TW_SHARED_BUF_ALLOC_UNITS = 0x55, +#endif +#if defined(UFS3V0) + DEVICE_DESC_PARAM_TW_VER = 0x55, +#endif +#endif }; /* Interconnect descriptor parameters offsets in bytes*/ @@ -258,6 +293,25 @@ 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) +#if defined(UFS3V1) + GEOMETRY_DESC_TW_GROUP_NUM_CAP = 0x4E, +#endif + 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, +#if defined(UFS3V0) + GEOMETRY_DESC_TW_GROUP_NUM_CAP = 0x57, +#endif +#endif }; /* Health descriptor parameters offsets in bytes*/ @@ -310,6 +364,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/ufs30/ufsfeature.c b/drivers/scsi/ufs/ufs30/ufsfeature.c new file mode 100644 index 000000000000..c0e35b1f7d8c --- /dev/null +++ b/drivers/scsi/ufs/ufs30/ufsfeature.c @@ -0,0 +1,710 @@ +/* + * 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; +} + +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; + + 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_work(&ufsf->tw_reset_work); +} + +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_work(&ufsf->tw_reset_work); +} + +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/ufs30/ufsfeature.h b/drivers/scsi/ufs/ufs30/ufsfeature.h new file mode 100644 index 000000000000..a20c6d702ccf --- /dev/null +++ b/drivers/scsi/ufs/ufs30/ufsfeature.h @@ -0,0 +1,208 @@ +/* + * 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 work_struct 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; + +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); +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/ufs30/ufshpb.c b/drivers/scsi/ufs/ufs30/ufshpb.c new file mode 100644 index 000000000000..87dee63a626a --- /dev/null +++ b/drivers/scsi/ufs/ufs30/ufshpb.c @@ -0,0 +1,3691 @@ +/* + * 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"); +} + +extern int ufs_fill_info(struct ufs_hba *hba); +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; + + ufs_fill_info(ufsf->hba); + + 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/ufs30/ufshpb.h b/drivers/scsi/ufs/ufs30/ufshpb.h new file mode 100644 index 000000000000..73ff3a302fa3 --- /dev/null +++ b/drivers/scsi/ufs/ufs30/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/ufs30/ufstw.c b/drivers/scsi/ufs/ufs30/ufstw.c new file mode 100644 index 000000000000..326d23a6b5ab --- /dev/null +++ b/drivers/scsi/ufs/ufs30/ufstw.c @@ -0,0 +1,1549 @@ +/* + * 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; + + 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_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_work(&ufsf->tw_reset_work); + TW_DEBUG(ufsf, "flush_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_work_sync(&ufsf->tw_reset_work); + RELEASE_INFO("cancel_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; + } + + 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); + 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) + tw->tw_enable = false; + } + + if (tw->tw_flush_enable) { + ret = ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable); + if (ret) + tw->tw_flush_enable = false; + } + + 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) + tw->tw_flush_during_hibern_enter = false; + } + + 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)); +} + +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 *work) +{ + struct ufsf_feature *ufsf; + int ret; + + ufsf = container_of(work, struct ufsf_feature, tw_reset_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/ufs30/ufstw.h b/drivers/scsi/ufs/ufs30/ufstw.h new file mode 100644 index 000000000000..c0165b0048e4 --- /dev/null +++ b/drivers/scsi/ufs/ufs30/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 0x0110 + +#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/scsi/ufs/ufs31/ufsfeature.c b/drivers/scsi/ufs/ufs31/ufsfeature.c new file mode 100644 index 000000000000..c7588ceac469 --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufsfeature.c @@ -0,0 +1,750 @@ +/* + * 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" + +#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; + + BUG_ON(idx > 7); + + 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]; + INFO_MSG("device lu count %d", ufsf->num_lu); + + INFO_MSG("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_FEAT_SUP], + 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, desc_buf); +#endif + +#if defined(CONFIG_UFSTW) + ufstw_get_dev_info(ufsf, 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 (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + ufshpb_get_geo_info(ufsf, geo_buf); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_get_geo_info(ufsf, geo_buf); +#endif + return 0; +} + +static void 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; + +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + ufshpb_get_lu_info(ufsf, lun, unit_buf); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_alloc_lu(ufsf, lun, unit_buf); +#endif +out: + return; +} + +int is_samsung_ufs(struct ufs_hba *hba) +{ + int is_samsung_ufs = 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) + is_samsung_ufs = 1; + } + + return is_samsung_ufs; +} + +void ufsf_device_check(struct ufs_hba *hba) +{ + struct ufsf_feature *ufsf = &hba->ufsf; + int ret, lun; + u32 status; + + ufsf->hba = hba; + + if (!is_samsung_ufs(hba)) { + ufshpb_set_state(ufsf, HPB_FAILED); + ufstw_set_state(ufsf, TW_FAILED); + return; + } + + ufshcd_query_attr(ufsf->hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS, 0, 0, &status); + INFO_MSG("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) + ufsf_read_unit_desc(ufsf, lun, UFSFEATURE_SELECTOR); +} + +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; +} + +static inline void ufsf_set_read10_debug_cmd(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); +} + +static int ufsf_execute_read10_debug(struct ufsf_feature *ufsf, int lun, + unsigned char *cdb, void *buf, int len) +{ + struct scsi_sense_hdr sshdr; + struct scsi_device *sdev; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[lun]; + if (!sdev) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufsf_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + ufsf->issue_read10_debug = true; + + ret = scsi_execute(sdev, cdb, DMA_FROM_DEVICE, buf, len, NULL, &sshdr, + msecs_to_jiffies(30000), 3, 0, 0, NULL); + + ufsf->issue_read10_debug = false; + + scsi_device_put(sdev); + + return ret; +} + +int ufsf_issue_read10_debug(struct ufsf_feature *ufsf, int lun, + unsigned char *buf, int buf_len) +{ + unsigned char cdb[10] = { 0 }; + int cmd_len = buf_len >> OS_PAGE_SHIFT; + int ret = 0; + + ufsf_set_read10_debug_cmd(cdb, READ10_DEBUG_LBA, cmd_len); + + ret = ufsf_execute_read10_debug(ufsf, lun, cdb, buf, buf_len); + + if (ret < 0) + ERR_MSG("failed with err %d", ret); + + return ret; +} + +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 (!ufs_is_valid_unit_desc_lun(lun)) { + ERR_MSG("No unit descriptor for lun 0x%x", lun); + err = -EINVAL; + goto out_release_mem; + } + err = ufsf_issue_read10_debug(ufsf, lun, kernel_buf, + ioctl_data->buf_size); + if (err < 0) + goto out_release_mem; + + goto copy_buffer; + 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; + +copy_buffer: + 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 int ufsf_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); + ERR_MSG("scsi_device_get failed.(%d)", ret); + return -ENODEV; + } + spin_unlock_irqrestore(hba->host->host_lock, flags); + + return ret; +} + +inline bool ufsf_is_valid_lun(int lun) +{ + return lun < UFS_UPIU_MAX_GENERAL_LUN; +} + +inline void ufsf_slave_configure(struct ufsf_feature *ufsf, + struct scsi_device *sdev) +{ + if (ufsf_is_valid_lun(sdev->lun)) { + ufsf->sdev_ufs_lu[sdev->lun] = sdev; + ufsf->slave_conf_cnt++; + INFO_MSG("lun[%d] sdev(%p) q(%p) slave_conf_cnt(%d/%d)", + (int)sdev->lun, sdev, sdev->request_queue, + ufsf->slave_conf_cnt, ufsf->num_lu); + +#if defined(CONFIG_UFSHPB) + if (ufsf->num_lu == ufsf->slave_conf_cnt) { + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { + INFO_MSG("wakeup ufshpb_init_handler"); + wake_up(&ufsf->hpb_wait); + } + } +#endif + } +} + +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); +} + +inline void ufsf_change_read10_debug_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ + int ctx_lba = LI_EN_32(lrbp->cmd->cmnd + 2); + + if (ufsf->issue_read10_debug == 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_prep_fn(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_PRESENT && + ufsf->issue_read10_debug == false) + ufshpb_prep_fn(ufsf, lrbp); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_prep_fn(ufsf, lrbp); +#endif +} + +inline void ufsf_reset_lu(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSTW) + INFO_MSG("run reset_lu.. tw_state(%d) -> TW_RESET", + ufstw_get_state(ufsf)); + ufstw_set_state(ufsf, TW_RESET); + ufstw_reset(ufsf, false); +#endif +} + +inline void ufsf_reset_host(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + INFO_MSG("run reset_host.. hpb_state(%d) -> HPB_RESET", + ufshpb_get_state(ufsf)); + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_reset_host(ufsf); +#endif + +#if defined(CONFIG_UFSTW) + INFO_MSG("run reset_host.. tw_state(%d) -> TW_RESET", + ufstw_get_state(ufsf)); + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_reset_host(ufsf); +#endif +} + +inline void ufsf_init(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { + INFO_MSG("init start.. hpb_state (%d)", HPB_NEED_INIT); + schedule_work(&ufsf->hpb_init_work); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_init(ufsf); +#endif +} + +inline void ufsf_reset(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_RESET) { + INFO_MSG("reset start.. hpb_state %d", HPB_RESET); + ufshpb_reset(ufsf); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_RESET && + !ufsf->hba->pm_op_in_progress) { + INFO_MSG("reset start.. tw_state %d", + ufstw_get_state(ufsf)); + ufstw_reset(ufsf, false); + } +#endif +} + +inline void ufsf_remove(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_remove(ufsf, HPB_NEED_INIT); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_remove(ufsf); +#endif +} + +inline void ufsf_set_init_state(struct ufsf_feature *ufsf) +{ + ufsf->slave_conf_cnt = 0; + ufsf->issue_read10_debug = false; +#if defined(CONFIG_UFSHPB) + ufshpb_set_state(ufsf, HPB_NEED_INIT); + INIT_WORK(&ufsf->hpb_init_work, ufshpb_init_handler); + init_waitqueue_head(&ufsf->hpb_wait); +#endif +#if defined(CONFIG_UFSW) + ufstw_set_state(ufsf, TW_NEED_INIT); +#endif +} + +inline void ufsf_resume(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_SUSPEND || + ufshpb_get_state(ufsf) == HPB_PRESENT) { + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + WARN_MSG("warning.. hpb state PRESENT in resuming"); + ufshpb_resume(ufsf); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == HPB_RESET) + ufstw_reset(ufsf, true); +#endif +} + +/* + * 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 (ufshpb_get_state(ufsf) == 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 (ufshpb_get_state(ufsf) == 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_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_rsp_upiu(ufsf, lrbp); +} + +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) +{ + /* + * if suspend failed, pm could call the suspend function again, + * in this case, ufshpb state already had been changed to SUSPEND state. + * so, we will not call ufshpb_suspend. + */ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_suspend(ufsf); +} +#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_noti_rb(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) {} +#endif diff --git a/drivers/scsi/ufs/ufs31/ufsfeature.h b/drivers/scsi/ufs/ufs31/ufsfeature.h new file mode 100644 index 000000000000..cc3c0fb362ac --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufsfeature.h @@ -0,0 +1,191 @@ +/* + * 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 +#include +#include + +#include "ufs.h" + +#include "ufshpb.h" +#include "ufstw.h" + +/* Constant value*/ +#define SECTOR 512 +#define BLOCK 4096 +#define SECTORS_PER_BLOCK (BLOCK / SECTOR) +#define BITS_PER_DWORD 32 +#define sects_per_blk_shift 3 +#define bits_per_dword_shift 5 +#define bits_per_dword_mask 0x1F +#define bits_per_byte_shift 3 + +#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 0x5F +#define UFSF_QUERY_DESC_CONFIGURAION_MAX_SIZE 0xE6 +#define UFSF_QUERY_DESC_UNIT_MAX_SIZE 0x2D +#define UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE 0x59 + +#define UFSFEATURE_SELECTOR 0x01 + +/* query_flag */ +#define MASK_QUERY_UPIU_FLAG_LOC 0xFF + +/* For read10 debug */ +#define READ10_DEBUG_LUN 0x7F +#define READ10_DEBUG_LBA 0x48504230 + +/* 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...) pr_info("%s:%d info: " msg "\n", \ + __func__, __LINE__, ##args) +#define ERR_MSG(msg, args...) pr_err("%s:%d err: " msg "\n", \ + __func__, __LINE__, ##args) +#define WARN_MSG(msg, args...) pr_warn("%s:%d warn: " 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]; + bool issue_read10_debug; + +#if defined(CONFIG_UFSHPB) + struct ufshpb_dev_info hpb_dev_info; + struct ufshpb_lu *hpb_lup[UFS_UPIU_MAX_GENERAL_LUN]; + struct work_struct hpb_init_work; + struct work_struct hpb_eh_work; + wait_queue_head_t hpb_wait; + atomic_t hpb_state; + struct kref hpb_kref; +#endif +#if defined(CONFIG_UFSTW) + struct ufstw_dev_info tw_dev_info; + struct ufstw_lu *tw_lup[UFS_UPIU_MAX_GENERAL_LUN]; + atomic_t tw_state; +#endif +}; + +struct ufs_hba; +struct ufshcd_lrb; + +int is_samsung_ufs(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); +int ufsf_get_scsi_device(struct ufs_hba *hba, struct scsi_device *sdev); +bool ufsf_is_valid_lun(int lun); +void ufsf_slave_configure(struct ufsf_feature *ufsf, struct scsi_device *sdev); +int ufsf_get_ee_status(struct ufs_hba *hba, u32 *status); + +void ufsf_change_read10_debug_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp); +void ufsf_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_reset_lu(struct ufsf_feature *ufsf); +void ufsf_reset_host(struct ufsf_feature *ufsf); +void ufsf_init(struct ufsf_feature *ufsf); +void ufsf_reset(struct ufsf_feature *ufsf); +void ufsf_remove(struct ufsf_feature *ufsf); +void ufsf_set_init_state(struct ufsf_feature *ufsf); +void ufsf_resume(struct ufsf_feature *ufsf); + +/* 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_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_hpb_suspend(struct ufsf_feature *ufsf); +void ufsf_hpb_release(struct ufsf_feature *ufsf); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs31/ufshpb.c b/drivers/scsi/ufs/ufs31/ufshpb.c new file mode 100644 index 000000000000..89c694b22c99 --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufshpb.c @@ -0,0 +1,3815 @@ +/* + * 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 + +static int ufshpb_create_sysfs(struct ufsf_feature *ufsf, + struct ufshpb_lu *hpb); +static void 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 != HPB_RGN_INACTIVE && + srgn->srgn_state == HPB_SRGN_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 (unlikely(!srgn->mctx || !srgn->mctx->ppn_dirty)) + return true; + + if (hpb->entries_per_srgn < srgn_offset + scan_cnt) { + int cnt = hpb->entries_per_srgn - srgn_offset; + + find_size = hpb->entries_per_srgn; + scan_cnt -= cnt; + cur_lpn += cnt; + } 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; + + } while (scan_cnt); + + return false; +} + +static void ufshpb_set_read16_cmd(struct ufshpb_lu *hpb, + struct ufshcd_lrb *lrbp, + u64 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 == HPB_RGN_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 u64 ufshpb_get_ppn(struct ufshpb_map_ctx *mctx, int pos, int *error) +{ + u64 *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 (unlikely(!page)) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get m_page", mctx); + return 0; + } + + ppn_table = page_address(page); + if (unlikely(!ppn_table)) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get ppn_table vm", mctx); + return 0; + } + + return ppn_table[offset]; +} + +#if defined(CONFIG_HPB_ERR_INJECTION) +static u64 ufshpb_get_bitflip_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + return (ppn ^ hpb->err_injection_bitflip); +} + +static u64 ufshpb_get_offset_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + return (ppn + hpb->err_injection_offset); +} + +static u64 ufshpb_get_random_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + u64 random_ppn = 0; + + if (!hpb->err_injection_random) + return ppn; + + get_random_bytes(&random_ppn, sizeof(random_ppn)); + + return random_ppn; +} + +static u64 ufshpb_get_err_injection_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + u64 new_ppn = 0; + + if (hpb->err_injection_select == HPB_ERR_INJECTION_BITFLIP) + new_ppn = ufshpb_get_bitflip_ppn(hpb, ppn); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_OFFSET) + new_ppn = ufshpb_get_offset_ppn(hpb, ppn); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_RANDOM) + new_ppn = ufshpb_get_random_ppn(hpb, ppn); + + return new_ppn; +} +#endif + +inline int ufshpb_get_state(struct ufsf_feature *ufsf) +{ + return atomic_read(&ufsf->hpb_state); +} + +inline void ufshpb_set_state(struct ufsf_feature *ufsf, int state) +{ + atomic_set(&ufsf->hpb_state, state); +} + +static inline int ufshpb_lu_get(struct ufshpb_lu *hpb) +{ + if (!hpb || ufshpb_get_state(hpb->ufsf) != HPB_PRESENT) + return -ENODEV; + + kref_get(&hpb->ufsf->hpb_kref); + return 0; +} + +static inline void ufshpb_schedule_error_handler(struct kref *kref) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(kref, struct ufsf_feature, hpb_kref); + schedule_work(&ufsf->hpb_eh_work); +} + +static inline void ufshpb_lu_put(struct ufshpb_lu *hpb) +{ + kref_put(&hpb->ufsf->hpb_kref, ufshpb_schedule_error_handler); +} + +static void ufshpb_failed(struct ufshpb_lu *hpb, const char *f) +{ + ERR_MSG("ufshpb_driver failed. function (%s)", f); + ufshpb_set_state(hpb->ufsf, 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("block status %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; + u64 *addr; + u64 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; + + BUG_ON(!srgn->mctx); + + entry_ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) + goto mctx_error; + +#if defined(CONFIG_HPB_ERR_INJECTION) + if (hpb->err_injection_select != HPB_ERR_INJECTION_DISABLE) + entry_ppn = + ufshpb_get_err_injection_ppn(hpb, entry_ppn); +#endif + + 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 inline 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->hpb_lup[lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(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; + u64 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->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(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 == HPB_RGN_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 (unlikely(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 (unlikely(!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); +#if defined(CONFIG_HPB_ERR_INJECTION) + if (hpb->err_injection_select != HPB_ERR_INJECTION_DISABLE) + ppn = ufshpb_get_err_injection_ppn(hpb, ppn); +#endif + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + if (unlikely(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 == HPB_RGN_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 == HPB_RGN_INACTIVE) { + HPB_DEBUG(hpb, "%d - %d evicted", srgn->rgn_idx, + srgn->srgn_idx); + return; + } + srgn->srgn_state = HPB_SRGN_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 == HPB_RGN_INACTIVE) { + ERR_MSG("%d - %d evicted", srgn->rgn_idx, srgn->srgn_idx); + return; + } + srgn->srgn_state = HPB_SRGN_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; + u64 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 == HPB_RGN_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); + + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + spin_lock(&hpb->retry_list_lock); + list_add_tail(&map_req->list_req, + &hpb->lh_map_req_retry); + spin_unlock(&hpb->retry_list_lock); + + schedule_delayed_work(&hpb->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->task_work); + } + + return 0; +} + +#ifdef CONFIG_PM +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); +} +#endif + +/* 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 (ufshpb_get_state(hpb->ufsf) != 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 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 ufshpb_req *map_req) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct request *req; + struct scsi_cmnd *scmd; + struct bio *bio = map_req->bio; + struct scsi_request *rq; + int ret = 0; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufsf_get_scsi_device(hpb->ufsf->hba, sdev); + if (ret) + return ret; + + q = sdev->request_queue; + + ret = ufshpb_map_req_add_bio_page(hpb, q, bio, map_req->rb.mctx); + if (ret) { + scsi_device_put(sdev); + 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 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 = HPB_RGN_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 = HPB_SRGN_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 == HPB_SRGN_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 = HPB_RGN_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, HPB_SRGN_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 == HPB_SRGN_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 == HPB_RGN_PINNED) { + /* + * Pinned active-block should not drop-out. + * But if so, it would treat error as critical, + * and it will run hpb_eh_work + */ + ERR_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_issue_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 == HPB_SRGN_ISSUED) { + ret = -EAGAIN; + goto unlock_out; + } + + map_req = ufshpb_get_map_req(hpb); + if (!map_req) { + ret = -ENOMEM; + goto unlock_out; + } + + srgn->srgn_state = HPB_SRGN_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 (unlikely(ret)) { + ERR_MSG("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_execute_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 == HPB_RGN_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(=%lld). victim choose %d", + (long long)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 wakeup_ee_worker; + } + } +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return ret; +wakeup_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->task_work); +} + +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_task_work = false; + + if (!ufsf_is_valid_lun(lrbp->lun)) + return; + + hpb = ufsf->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) + return; + + do_task_work = !ufshpb_is_empty_rsp_lists(hpb); + if (do_task_work) + schedule_work(&hpb->task_work); + + 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->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + ERR_MSG("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) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + q = sdev->request_queue; + + ret = ufsf_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + req = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL); + if (IS_ERR(req)) { + ERR_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_pinned_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, pinned_work); + HPB_DEBUG(hpb, "worker start for pinned region"); + + pm_runtime_get_sync(hpb->ufsf->hba->dev); + ufshpb_lu_get(hpb); + + 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); + } + ufshpb_lu_put(hpb); + pm_runtime_put_sync(hpb->ufsf->hba->dev); + 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; + bool do_retry = false; + int ret = 0; + + LIST_HEAD(retry_list); + + hpb = container_of(dwork, struct ufshpb_lu, retry_work); + + if (ufshpb_check_pm(hpb)) + return; + + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + ERR_MSG("ufshpb_lu_get failed. (%d)", ret); + return; + } + + HPB_DEBUG(hpb, "retry worker start"); + + spin_lock_bh(&hpb->retry_list_lock); + list_splice_init(&hpb->lh_map_req_retry, &retry_list); + spin_unlock_bh(&hpb->retry_list_lock); + + list_for_each_entry_safe(map_req, next, &retry_list, list_req) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Issue READ_BUFFER in the next turn"); + spin_lock_bh(&hpb->retry_list_lock); + list_splice_init(&retry_list, &hpb->lh_map_req_retry); + spin_unlock_bh(&hpb->retry_list_lock); + do_retry = true; + break; + } + + list_del_init(&map_req->list_req); + + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + WARN_MSG("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_execute_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); + + if (do_retry) + schedule_delayed_work(&hpb->retry_work, + msecs_to_jiffies(RETRY_DELAY_MS)); + 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))) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Inactivate rgn the next turn"); + break; + } + + 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))) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Issuing READ_BUFFER the next turn"); + break; + } + + 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_issue_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_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, task_work); + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + if (hpb) + WARN_MSG("lu_get failed.. hpb_state %d", + ufshpb_get_state(hpb->ufsf)); + WARN_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 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 = HPB_SRGN_ISSUED; + /* + * no need to clean ppn_dirty bitmap + * because it is vzalloc-ed @ufshpb_table_mempool_init() + */ + list_add_tail(&srgn->list_act_srgn, &hpb->lh_pinned_srgn); + } + + rgn->rgn_state = HPB_RGN_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->pinned_work, ufshpb_pinned_work_handler); + INIT_DELAYED_WORK(&hpb->retry_work, ufshpb_retry_work_handler); + INIT_WORK(&hpb->task_work, ufshpb_task_work_handler); +} + +static inline void ufshpb_cancel_jobs(struct ufshpb_lu *hpb) +{ + cancel_work_sync(&hpb->pinned_work); + cancel_delayed_work_sync(&hpb->retry_work); + cancel_work_sync(&hpb->task_work); +} + +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 = HPB_SRGN_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++; + } + + INFO_MSG("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; + INFO_MSG("lu (%d) queue_depth (%d)", hpb->lun, hpb->qd); + if (!hpb->qd) { + hpb->qd = hba->nutrs; + INFO_MSG("lu_queue_depth is 0. we use device's queue info."); + INFO_MSG("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->rgn_size); + rgn_mem_size = rgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + hpb->srgn_unit_size = (unsigned long long) + SECTOR * (0x01 << hpb_dev_info->srgn_size); + hpb->srgn_mem_size = hpb->srgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + /* 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; + + INFO_MSG("===== From Device Descriptor! ====="); + INFO_MSG("hpb_region_size = (%d), hpb_subregion_size = (%d)", + hpb_dev_info->rgn_size, hpb_dev_info->srgn_size); + INFO_MSG("===== Constant Values(LU) ====="); + INFO_MSG("region_unit_size = (%lld), region_mem_size (%lld)", + rgn_unit_size, rgn_mem_size); + INFO_MSG("subregion_unit_size = (%lld), subregion_mem_size (%d)", + hpb->srgn_unit_size, hpb->srgn_mem_size); + + INFO_MSG("lu_num_blocks = (%d)", hpb->lu_num_blocks); + INFO_MSG("regions_per_lu = (%d), subregions_per_lu = (%d)", + hpb->rgns_per_lu, hpb->srgns_per_lu); + + INFO_MSG("subregions_per_region = %d", hpb->srgns_per_rgn); + INFO_MSG("entries_per_region (%u) shift (%u) mask (0x%X)", + entries_per_rgn, hpb->entries_per_rgn_shift, + hpb->entries_per_rgn_mask); + INFO_MSG("entries_per_subregion (%u) shift (%u) mask (0x%X)", + hpb->entries_per_srgn, hpb->entries_per_srgn_shift, + hpb->entries_per_srgn_mask); + INFO_MSG("mpages_per_subregion : (%d)", hpb->mpages_per_srgn); + INFO_MSG("==================================="); +} + +static int ufshpb_lu_hpb_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufshpb_lu *hpb = ufsf->hpb_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; + } + + INFO_MSG("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->retry_list_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; + INFO_MSG("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 = HPB_RGN_INACTIVE; + } + } + + if (total_srgn_cnt != 0) { + ERR_MSG("error total_subregion_count: %d", + total_srgn_cnt); + goto release_srgns; + } + + /* + * 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) +{ + INFO_MSG("Support HPB Spec : Driver = (%.4X) Device = (%.4X)", + UFSHPB_VER, hpb_dev_info->version); + + INFO_MSG("HPB Driver Version : (%.6X%s)", UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + if (hpb_dev_info->version != UFSHPB_VER) { + ERR_MSG("ERROR: HPB Spec Version mismatch. So HPB disabled."); + return -ENODEV; + } + return 0; +} + +void ufshpb_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) +{ + struct ufshpb_dev_info *hpb_dev_info = &ufsf->hpb_dev_info; + int ret; + + if (desc_buf[DEVICE_DESC_PARAM_FEAT_SUP] & UFS_FEATURE_SUPPORT_HPB_BIT) + INFO_MSG("bUFSFeaturesSupport: HPB is set"); + else { + INFO_MSG("bUFSFeaturesSupport: HPB not support"); + ufshpb_set_state(ufsf, HPB_FAILED); + return; + } + + hpb_dev_info->version = LI_EN_16(desc_buf + DEVICE_DESC_PARAM_HPB_VER); + + ret = ufshpb_version_check(hpb_dev_info); + if (ret) + ufshpb_set_state(ufsf, HPB_FAILED); +} + +void ufshpb_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf) +{ + struct ufshpb_dev_info *hpb_dev_info = &ufsf->hpb_dev_info; + int hpb_device_max_active_rgns = 0; + + hpb_dev_info->num_lu = geo_buf[GEOMETRY_DESC_HPB_NUMBER_LU]; + if (hpb_dev_info->num_lu == 0) { + ERR_MSG("Don't have a lu for hpb."); + ufshpb_set_state(ufsf, HPB_FAILED); + return; + } + + hpb_dev_info->rgn_size = geo_buf[GEOMETRY_DESC_HPB_REGION_SIZE]; + hpb_dev_info->srgn_size = geo_buf[GEOMETRY_DESC_HPB_SUBREGION_SIZE]; + hpb_device_max_active_rgns = + LI_EN_16(geo_buf + GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS); + + INFO_MSG("[48] bHPBRegionSiz (%u)", hpb_dev_info->rgn_size); + INFO_MSG("[49] bHPBNumberLU (%u)", hpb_dev_info->num_lu); + INFO_MSG("[4A] bHPBSubRegionSize (%u)", hpb_dev_info->srgn_size); + INFO_MSG("[4B:4C] wDeviceMaxActiveHPBRegions (%u)", + hpb_device_max_active_rgns); + + if (hpb_dev_info->rgn_size == 0 || hpb_dev_info->srgn_size == 0 || + hpb_device_max_active_rgns == 0) { + ERR_MSG("HPB NOT normally supported by device"); + ufshpb_set_state(ufsf, HPB_FAILED); + } +} + +void 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 = PINNED_NOT_SET; + + INFO_MSG("LUN(%d) [0A] bLogicalBlockSize (%d)", + lun, lu_desc.lu_logblk_size); + INFO_MSG("LUN(%d) [0B] qLogicalBlockCount (%llu)", + lun, lu_desc.lu_logblk_cnt); + INFO_MSG("LUN(%d) [03] bLuEnable (%d)", lun, lu_desc.lu_enable); + INFO_MSG("LUN(%d) [06] bLuQueueDepth (%d)", lun, lu_desc.lu_queue_depth); + INFO_MSG("LUN(%d) [23:24] wLUMaxActiveHPBRegions (%d)", + lun, lu_desc.lu_max_active_hpb_rgns); + INFO_MSG("LUN(%d) [25:26] wHPBPinnedRegionStartIdx (%d)", + lun, lu_desc.lu_hpb_pinned_rgn_startidx); + INFO_MSG("LUN(%d) [27:28] wNumHPBPinnedRegions (%d)", + lun, lu_desc.lu_num_hpb_pinned_rgns); + INFO_MSG("LUN(%d) PINNED Start (%d) End (%d)", + lun, lu_desc.lu_hpb_pinned_rgn_startidx, + lu_desc.lu_hpb_pinned_end_offset); + + ufsf->hpb_lup[lun] = NULL; + + if (lu_desc.lu_enable == 0x02 && lu_desc.lu_max_active_hpb_rgns) { + ufsf->hpb_lup[lun] = kzalloc(sizeof(struct ufshpb_lu), + GFP_KERNEL); + if (!ufsf->hpb_lup[lun]) { + ERR_MSG("hpb_lup[%d] alloc failed", lun); + return; + } + + hpb = ufsf->hpb_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 { + INFO_MSG("===== LU (%d) is hpb-disabled.", lun); + } +} + +static void ufshpb_error_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(work, struct ufsf_feature, hpb_eh_work); + + WARN_MSG("driver has failed. but UFSHCD can run without UFSHPB"); + WARN_MSG("UFSHPB will be removed from the kernel"); + + ufshpb_remove(ufsf, HPB_FAILED); +} + +static int ufshpb_init(struct ufsf_feature *ufsf) +{ + int lun, ret; + struct ufshpb_lu *hpb; + int hpb_enabled_lun = 0; + + seq_scan_lu(lun) { + if (!ufsf->hpb_lup[lun]) + continue; + + /* + * HPB need info about request queue in order to issue + * RB-CMD for pinned region. + */ + if (!ufsf->sdev_ufs_lu[lun]) { + WARN_MSG("lun (%d) don't have scsi_device", lun); + continue; + } + + ret = ufshpb_lu_hpb_init(ufsf, lun); + if (ret) { + kfree(ufsf->hpb_lup[lun]); + continue; + } + hpb_enabled_lun++; + } + + if (hpb_enabled_lun == 0) { + ERR_MSG("No UFSHPB LU to init"); + ret = -ENODEV; + goto hpb_failed; + } + + INIT_WORK(&ufsf->hpb_eh_work, ufshpb_error_handler); + + kref_init(&ufsf->hpb_kref); + ufshpb_set_state(ufsf, HPB_PRESENT); + + seq_scan_lu(lun) + if (ufsf->hpb_lup[lun]) { + hpb = ufsf->hpb_lup[lun]; + + INFO_MSG("UFSHPB LU %d working", lun); + if (hpb->lu_pinned_end_offset != PINNED_NOT_SET) + schedule_work(&hpb->pinned_work); + } + + return 0; +hpb_failed: + ufshpb_set_state(ufsf, 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 = HPB_SRGN_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; + + INFO_MSG("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 == HPB_RGN_PINNED || + rgn->rgn_state == HPB_RGN_ACTIVE) { + rgn->rgn_state = HPB_RGN_INACTIVE; + + ufshpb_destroy_subregion_tbl(hpb, rgn); + } + } + + ufshpb_table_mempool_remove(hpb); + kfree(hpb->rgn_tbl); + + INFO_MSG("End"); +} + +void ufshpb_remove(struct ufsf_feature *ufsf, int state) +{ + struct ufshpb_lu *hpb; + int lun; + + INFO_MSG("start release"); + ufshpb_set_state(ufsf, HPB_FAILED); + + INFO_MSG("kref count (%d)", + atomic_read(&ufsf->hpb_kref.refcount.refs)); + + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + + INFO_MSG("lun (%d) (%p)", lun, hpb); + + ufsf->hpb_lup[lun] = NULL; + + if (!hpb) + continue; + + ufshpb_cancel_jobs(hpb); + + ufshpb_destroy_region_tbl(hpb); + if (hpb->alloc_mctx != 0) + WARN_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); + } + + ufshpb_set_state(ufsf, state); + + INFO_MSG("end release"); +} + +void ufshpb_reset(struct ufsf_feature *ufsf) +{ + ufshpb_set_state(ufsf, HPB_PRESENT); +} + +void ufshpb_reset_host(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + ufshpb_set_state(ufsf, HPB_RESET); + seq_scan_lu(lun) { + hpb = ufsf->hpb_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); + } + } +} + +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 = 0; + + ufsf = container_of(work, struct ufsf_feature, hpb_init_work); + + INFO_MSG("probe_done(%d)", ufshpb_probe_lun_done(ufsf)); + + ret = wait_event_timeout(ufsf->hpb_wait, + ufshpb_probe_lun_done(ufsf), + msecs_to_jiffies(10000)); + if (ret == 0) + ERR_MSG("Probing LU is not fully complete."); + + INFO_MSG("probe_done(%d) ret(%d)", ufshpb_probe_lun_done(ufsf), ret); + INFO_MSG("HPB_INIT_START"); + + ret = ufshpb_init(ufsf); + if (ret) + ERR_MSG("UFSHPB driver init failed. (%d)", ret); +} + +void ufshpb_suspend(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + if (hpb) { + INFO_MSG("ufshpb_lu %d goto suspend", lun); + INFO_MSG("ufshpb_lu %d changes suspend state", lun); + ufshpb_set_state(ufsf, HPB_SUSPEND); + ufshpb_cancel_jobs(hpb); + } + } +} + +void ufshpb_resume(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + if (hpb) { + bool do_task_work = false; + bool do_retry_work = false; + + ufshpb_set_state(ufsf, HPB_PRESENT); + + do_task_work = !ufshpb_is_empty_rsp_lists(hpb); + do_retry_work = + !list_empty_careful(&hpb->lh_map_req_retry); + + INFO_MSG("ufshpb_lu %d resume. do_task_work %d retry %d", + lun, do_task_work, do_retry_work); + + if (do_task_work) + schedule_work(&hpb->task_work); + if (do_retry_work) + schedule_delayed_work(&hpb->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); + + INFO_MSG("force_hpb_read_disable %d", hpb->force_disable); + 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; + + INFO_MSG("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); + + INFO_MSG("force_map_req_disable %d", hpb->force_map_req_disable); + + 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; + + INFO_MSG("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); + + INFO_MSG("throttle_map_req %d", hpb->throttle_map_req); + + 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; + + INFO_MSG("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); + + INFO_MSG("throttle_pre_req %d", hpb->throttle_pre_req); + + 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; + + INFO_MSG("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); + INFO_MSG("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) + INFO_MSG("value is wrong. pre_req transfer len %d ~ %d", + HPB_MULTI_CHUNK_LOW, hpb->pre_req_max_tr_len); + else + hpb->pre_req_min_tr_len = val; + + INFO_MSG("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); + INFO_MSG("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) + INFO_MSG("value is wrong. pre_req transfer len %d ~ %d", + hpb->pre_req_min_tr_len, HPB_MULTI_CHUNK_HIGH); + else + hpb->pre_req_max_tr_len = val; + + INFO_MSG("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); + + INFO_MSG("debug %d", hpb->debug); + + 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; + + INFO_MSG("debug %d", hpb->debug); + + return cnt; +} + +#if defined(CONFIG_HPB_ERR_INJECTION) +static ssize_t ufshpb_sysfs_err_injection_select_show(struct ufshpb_lu *hpb, + char *buf) +{ + char error_injection[8]; + int ret; + + if (hpb->err_injection_select == HPB_ERR_INJECTION_DISABLE) + strlcpy(error_injection, "disable", 8); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_BITFLIP) + strlcpy(error_injection, "bitflip", 8); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_OFFSET) + strlcpy(error_injection, "offset", 7); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_RANDOM) + strlcpy(error_injection, "random", 7); + + ret = snprintf(buf, PAGE_SIZE, "err_injection_select %s\n", + error_injection); + + INFO_MSG("err_injection_select %s", error_injection); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_select_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + char error_injection[8]; + int ret; + + error_injection[7] = '\0'; + + ret = sscanf(buf, "%7s", error_injection); + if (!ret) { + INFO_MSG("input failed..."); + return cnt; + } + + if (!strncmp(error_injection, "disable", 7)) + hpb->err_injection_select = HPB_ERR_INJECTION_DISABLE; + else if (!strncmp(error_injection, "bitflip", 7)) + hpb->err_injection_select = HPB_ERR_INJECTION_BITFLIP; + else if (!strncmp(error_injection, "offset", 6)) + hpb->err_injection_select = HPB_ERR_INJECTION_OFFSET; + else if (!strncmp(error_injection, "random", 6)) + hpb->err_injection_select = HPB_ERR_INJECTION_RANDOM; + else { + hpb->err_injection_select = HPB_ERR_INJECTION_DISABLE; + strlcpy(error_injection, "disable", 8); + } + + INFO_MSG("err_injection_select %s", error_injection); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_bitflip_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_bitflip %llx\n", + hpb->err_injection_bitflip); + + INFO_MSG("err_injection_bitflip %llx", hpb->err_injection_bitflip); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_bitflip_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long long err_injection_bitflip; + + if (kstrtoull(buf, 0, &err_injection_bitflip)) + return -EINVAL; + + hpb->err_injection_bitflip = err_injection_bitflip; + + INFO_MSG("err_injection_bitflip %llx", hpb->err_injection_bitflip); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_offset_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_offset %lld\n", + hpb->err_injection_offset); + + INFO_MSG("err_injection_offset %lld", hpb->err_injection_offset); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_offset_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long long err_injection_offset; + + if (kstrtoull(buf, 0, &err_injection_offset)) + return -EINVAL; + + hpb->err_injection_offset = err_injection_offset; + + INFO_MSG("err_injection_offset %lld", hpb->err_injection_offset); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_random_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_random %d\n", + hpb->err_injection_random); + + INFO_MSG("err_injection_random %d", hpb->err_injection_random); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_random_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long err_injection_random; + + if (kstrtoul(buf, 0, &err_injection_random)) + return -EINVAL; + + if (err_injection_random >= 1) + hpb->err_injection_random = 1; + else + hpb->err_injection_random = 0; + + INFO_MSG("err_injection_random %d", hpb->err_injection_random); + + return cnt; +} +#endif + +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 %.6X%s\n", + hpb->ufsf->hpb_dev_info.version, + UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + INFO_MSG("HPB version %.4X D/D version %.6X%s", + hpb->ufsf->hpb_dev_info.version, + UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + 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); + + INFO_MSG("hit_count %lld", hit_cnt); + + 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); + + INFO_MSG("miss_count %lld", miss_cnt); + + 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); + + INFO_MSG("rb_noti %lld ACT %lld INACT %lld map_req_count %lld", + rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, + map_req_cnt); + + 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); + + INFO_MSG("pre_req_count %lld", pre_req_cnt); + + 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 HPB_RGN_STATE state; + + for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { + state = hpb->rgn_tbl[rgn_idx].rgn_state; + if (state == HPB_RGN_PINNED) + pin_cnt++; + else if (state == HPB_RGN_ACTIVE) + act_cnt++; + else if (state == HPB_RGN_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); + + INFO_MSG("Total %d pinned %d active %d inactive %d", + 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; + + INFO_MSG("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; + u64 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); + INFO_MSG("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)) { + INFO_MSG("[region %d subregion %d] has not valid hpb info.", + rgn_idx, srgn_idx); + goto out; + } + + if (!srgn->mctx) { + INFO_MSG("mctx is NULL"); + goto out; + } + + ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) { + INFO_MSG("getting ppn is fail from a page."); + goto out; + } + + INFO_MSG("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 { + INFO_MSG("(region state : PINNED=%d ACTIVE=%d INACTIVE=%d)", + HPB_RGN_PINNED, HPB_RGN_ACTIVE, HPB_RGN_INACTIVE); + + INFO_MSG("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++) { + INFO_MSG("--- 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; + + INFO_MSG("start release function"); + + if (kstrtoul(buf, 0, &value)) { + ERR_MSG("kstrtoul error"); + return -EINVAL; + } + + if (value == 0xab) { + INFO_MSG("magic number %lu release start", value); + goto err_out; + } else + INFO_MSG("wrong magic number %lu", value); + + return cnt; +err_out: + INFO_MSG("ref_cnt %d", + atomic_read(&hpb->ufsf->hpb_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), +#if defined(CONFIG_HPB_ERR_INJECTION) + __ATTR(err_injection_select, 0644, + ufshpb_sysfs_err_injection_select_show, + ufshpb_sysfs_err_injection_select_store), + __ATTR(err_injection_bitflip, 0644, + ufshpb_sysfs_err_injection_bitflip_show, + ufshpb_sysfs_err_injection_bitflip_store), + __ATTR(err_injection_offset, 0644, + ufshpb_sysfs_err_injection_offset_show, + ufshpb_sysfs_err_injection_offset_store), + __ATTR(err_injection_random, 0644, + ufshpb_sysfs_err_injection_random_show, + ufshpb_sysfs_err_injection_random_store), +#endif + __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); + + INFO_MSG("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++) { + INFO_MSG("ufshpb_lu%d sysfs attr creates: %s", + hpb->lun, entry->attr.name); + if (sysfs_create_file(&hpb->kobj, &entry->attr)) + break; + } + INFO_MSG("ufshpb_lu%d sysfs adds uevent", hpb->lun); + kobject_uevent(&hpb->kobj, KOBJ_ADD); + } + + return err; +} + +static inline void ufshpb_remove_sysfs(struct ufshpb_lu *hpb) +{ + kobject_uevent(&hpb->kobj, KOBJ_REMOVE); + INFO_MSG("ufshpb removes sysfs lu %d %p ", hpb->lun, &hpb->kobj); + kobject_del(&hpb->kobj); +} diff --git a/drivers/scsi/ufs/ufs31/ufshpb.h b/drivers/scsi/ufs/ufs31/ufshpb.h new file mode 100644 index 000000000000..e920a59a067a --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufshpb.h @@ -0,0 +1,343 @@ +/* + * 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 + +#if defined(CONFIG_HPB_ERR_INJECTION) +#include +#endif + +#include "../../../../block/blk.h" +#include "../../scsi_priv.h" + +/* Version info*/ +#define UFSHPB_VER 0x0201 +#define UFSHPB_DD_VER 0x020400 +#define UFSHPB_DD_VER_POST "" + +/* 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 + +#define PINNED_NOT_SET (-1) +/* + * 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_SUSPEND = 2, + HPB_FAILED = -2, + HPB_NEED_INIT = 0, + HPB_RESET = -3, +}; + +enum HPB_RGN_STATE { + HPB_RGN_INACTIVE, + HPB_RGN_ACTIVE, + HPB_RGN_PINNED, +}; + +enum HPB_SRGN_STATE { + HPB_SRGN_UNUSED, + HPB_SRGN_DIRTY, + HPB_SRGN_CLEAN, + HPB_SRGN_ISSUED, +}; + +#if defined(CONFIG_HPB_ERR_INJECTION) +enum HPB_ERR_INJECTION_SELECT { + HPB_ERR_INJECTION_DISABLE, + HPB_ERR_INJECTION_BITFLIP, + HPB_ERR_INJECTION_OFFSET, + HPB_ERR_INJECTION_RANDOM, +}; +#endif + +struct ufshpb_dev_info { + int num_lu; + int version; + int rgn_size; + int srgn_size; +}; + +struct ufshpb_active_field { + __be16 active_rgn; + __be16 active_srgn; +} __packed; + +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]; +} __packed; + +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 HPB_SRGN_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 HPB_RGN_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; + + spinlock_t retry_list_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 pinned_work; + struct delayed_work retry_work; + struct work_struct task_work; + + /* for selecting victim */ + struct victim_select_info lru_info; + + int lu_max_active_rgns; + int lu_pinned_rgn_startidx; + int lu_pinned_end_offset; + 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; +#if defined(CONFIG_HPB_ERR_INJECTION) + enum HPB_ERR_INJECTION_SELECT err_injection_select; + u64 err_injection_bitflip; + u64 err_injection_offset; + int err_injection_random; +#endif +}; + +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_get_state(struct ufsf_feature *ufsf); +void ufshpb_set_state(struct ufsf_feature *ufsf, int state); +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 ufsf_feature *ufsf, u8 *desc_buf); +void ufshpb_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf); +void ufshpb_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *unit_buf); +void ufshpb_init_handler(struct work_struct *work); +void ufshpb_rsp_upiu(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +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); +void ufshpb_reset_host(struct ufsf_feature *ufsf); +void ufshpb_reset(struct ufsf_feature *ufsf); +void ufshpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufshpb_remove(struct ufsf_feature *ufsf, int state); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs31/ufstw.c b/drivers/scsi/ufs/ufs31/ufstw.c new file mode 100644 index 000000000000..aaaba578685f --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufstw.c @@ -0,0 +1,901 @@ +/* + * 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); + +inline int ufstw_get_state(struct ufsf_feature *ufsf) +{ + return atomic_read(&ufsf->tw_state); +} + +inline void ufstw_set_state(struct ufsf_feature *ufsf, int state) +{ + atomic_set(&ufsf->tw_state, state); +} + +static int ufstw_is_not_present(struct ufsf_feature *ufsf) +{ + enum UFSTW_STATE cur_state = ufstw_get_state(ufsf); + + if (cur_state != TW_PRESENT) { + INFO_MSG("tw_state != TW_PRESENT (%d)", cur_state); + return -ENODEV; + } + return 0; +} + +#define FLAG_IDN_NAME(idn) \ + (idn == QUERY_FLAG_IDN_TW_EN ? "tw_enable" : \ + idn == QUERY_FLAG_IDN_TW_BUF_FLUSH_EN ? "flush_enable" : \ + idn == QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN ? \ + "flush_hibern" : "unknown") + +#define ATTR_IDN_NAME(idn) \ + (idn == QUERY_ATTR_IDN_TW_FLUSH_STATUS ? "flush_status" : \ + idn == QUERY_ATTR_IDN_TW_AVAIL_BUF_SIZE ? "avail_buffer_size" :\ + idn == QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST ? "lifetime_est" : \ + idn == QUERY_ATTR_IDN_TW_CURR_BUF_SIZE ? "current_buf_size" : \ + "unknown") + +static int ufstw_read_lu_attr(struct ufstw_lu *tw, u8 idn, u32 *attr_val) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + u32 val; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, + (u8)lun, &val); + if (err) { + ERR_MSG("read attr [0x%.2X](%s) failed. (%d)", idn, + ATTR_IDN_NAME(idn), err); + goto out; + } + + *attr_val = val; + + INFO_MSG("read attr LUN(%d) [0x%.2X](%s) success (%u)", + lun, idn, ATTR_IDN_NAME(idn), *attr_val); +out: + return err; +} + +static int ufstw_set_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("set flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = true; + + INFO_MSG("set flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +static int ufstw_clear_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("clear flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = false; + + INFO_MSG("clear flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +static int ufstw_read_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + bool val; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, idn, + (u8)lun, &val); + if (err) { + ERR_MSG("read flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = val; + + INFO_MSG("read flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +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 void ufstw_switch_disable_state(struct ufstw_lu *tw) +{ + int err = 0; + + WARN_MSG("dTurboWriteBUfferLifeTImeEst (0x%.2X)", tw->lifetime_est); + WARN_MSG("tw-mode will change to disable-mode"); + + mutex_lock(&tw->sysfs_lock); + ufstw_set_state(tw->ufsf, TW_FAILED); + mutex_unlock(&tw->sysfs_lock); + + if (tw->tw_enable) { + pm_runtime_get_sync(tw->ufsf->hba->dev); + err = ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable); + pm_runtime_put_sync(tw->ufsf->hba->dev); + if (err) + WARN_MSG("tw_enable flag clear failed"); + } +} + +static int ufstw_check_lifetime_not_guarantee(struct ufstw_lu *tw) +{ + bool disable_flag = false; + + if (tw->lifetime_est & MASK_UFSTW_LIFETIME_NOT_GUARANTEE) { + if (tw->lun == TW_LU_SHARED) + WARN_MSG("lun-shared lifetime_est[31] (1)"); + else + WARN_MSG("lun %d lifetime_est[31] (1)", + tw->lun); + + WARN_MSG("Device not guarantee the lifetime of TW Buffer"); +#if defined(CONFIG_UFSTW_IGNORE_GUARANTEE_BIT) + WARN_MSG("but we will ignore them for PoC"); +#else + disable_flag = true; +#endif + } + + if (disable_flag || + (tw->lifetime_est & ~MASK_UFSTW_LIFETIME_NOT_GUARANTEE) >= + UFSTW_MAX_LIFETIME_VALUE) { + ufstw_switch_disable_state(tw); + return -ENODEV; + } + + return 0; +} + +static void ufstw_lifetime_work_fn(struct work_struct *work) +{ + struct ufstw_lu *tw; + int ret; + + tw = container_of(work, struct ufstw_lu, tw_lifetime_work); + + if (ufstw_is_not_present(tw->ufsf)) + return; + + pm_runtime_get_sync(tw->ufsf->hba->dev); + ret = ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + &tw->lifetime_est); + pm_runtime_put_sync(tw->ufsf->hba->dev); + if (ret) + return; + + ufstw_check_lifetime_not_guarantee(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 (!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; + } + spin_unlock_bh(&tw->lifetime_lock); + + TMSG(tw->ufsf, lrbp->lun, "%s:%d tw_lifetime_work %u", + __func__, __LINE__, tw->stat_write_sec); +} + +static inline void ufstw_init_lu_jobs(struct ufstw_lu *tw) +{ + 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_work_sync(&tw->tw_lifetime_work); + INFO_MSG("cancel_work_sync(tw_lifetime_work) ufstw_lu[%d] (%d)", + tw->lun, ret); +} + +static inline int ufstw_version_mismatched(struct ufstw_dev_info *tw_dev_info) +{ + INFO_MSG("Support TW Spec : Driver = %.4X, Device = %.4X", + UFSTW_VER, tw_dev_info->tw_ver); + + INFO_MSG("TW Driver Version : %.6X%s", UFSTW_DD_VER, + UFSTW_DD_VER_POST); + + if (tw_dev_info->tw_ver != UFSTW_VER) + return -ENODEV; + + return 0; +} + +void ufstw_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) +{ + struct ufstw_dev_info *tw_dev_info = &ufsf->tw_dev_info; + + if (LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP]) & + UFS_FEATURE_SUPPORT_TW_BIT) { + INFO_MSG("bUFSExFeaturesSupport: TW is set"); + } else { + ERR_MSG("bUFSExFeaturesSupport: TW not support"); + ufstw_set_state(ufsf, TW_FAILED); + 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_shared_buf_alloc_units = + LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_TW_SHARED_BUF_ALLOC_UNITS]); + tw_dev_info->tw_ver = LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_TW_VER]); + + if (ufstw_version_mismatched(tw_dev_info)) { + ERR_MSG("TW Spec Version mismatch. TW disabled"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } + + 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); + INFO_MSG("tw_dev [55] dNumSharedTUrboWriteBufferAllocUnits (%u)", + tw_dev_info->tw_shared_buf_alloc_units); + + if (tw_dev_info->tw_buf_type == TW_BUF_TYPE_SHARED && + tw_dev_info->tw_shared_buf_alloc_units == 0) { + ERR_MSG("TW use shared buffer. But alloc unit is (0)"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } +} + +void ufstw_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf) +{ + struct ufstw_dev_info *tw_dev_info = &ufsf->tw_dev_info; + + 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"); + ufstw_set_state(ufsf, TW_FAILED); + 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] bSupportedTWBufferUserSpaceReductionTypes (%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]); +} + +static void ufstw_alloc_shared_lu(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + + tw = kzalloc(sizeof(struct ufstw_lu), GFP_KERNEL); + if (!tw) { + ERR_MSG("ufstw_lu[shared] memory alloc failed"); + return; + } + + tw->lun = TW_LU_SHARED; + tw->ufsf = ufsf; + ufsf->tw_lup[0] = tw; + + INFO_MSG("ufstw_lu[shared] is TurboWrite-Enabled"); +} + +static void 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_WRITE_BUFFER_ALLOC_UNIT]); + + 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]) { + ERR_MSG("ufstw_lu[%d] memory alloc faield", lun); + return; + } + + tw = ufsf->tw_lup[lun]; + tw->ufsf = ufsf; + tw->lun = lun; + INFO_MSG("ufstw_lu[%d] [29:2C] dLUNumTWBufferAllocUnits (%u)", + lun, lu_desc.tw_lu_buf_size); + INFO_MSG("ufstw_lu[%d] is TurboWrite-Enabled.", lun); + } else { + INFO_MSG("ufstw_lu[%d] [29:2C] dLUNumTWBufferAllocUnits (%u)", + lun, lu_desc.tw_lu_buf_size); + INFO_MSG("ufstw_lu[%d] is TurboWrite-disabled", lun); + } +} + +inline void ufstw_alloc_lu(struct ufsf_feature *ufsf, + int lun, u8 *lu_buf) +{ + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED && + !ufsf->tw_lup[0]) + ufstw_alloc_shared_lu(ufsf); + else if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_LU) + ufstw_get_lu_info(ufsf, lun, lu_buf); +} + +static inline void ufstw_print_lu_flag_attr(struct ufstw_lu *tw) +{ + char lun_str[20] = { 0 }; + + if (tw->lun == TW_LU_SHARED) + snprintf(lun_str, 7, "shared"); + else + snprintf(lun_str, 2, "%d", tw->lun); + + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) tw_enable (%d)", + lun_str, QUERY_FLAG_IDN_TW_EN, tw->tw_enable); + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) flush_enable (%d)", + lun_str, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + tw->flush_enable); + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) flush_hibern (%d)", + lun_str, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + tw->flush_during_hibern_enter); + + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) flush_status (%u)", + lun_str, QUERY_ATTR_IDN_TW_FLUSH_STATUS, tw->flush_status); + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) buffer_size (%u)", + lun_str, QUERY_ATTR_IDN_TW_AVAIL_BUF_SIZE, + tw->available_buffer_size); + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) buffer_lifetime (0x%.2X)", + lun_str, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + tw->lifetime_est); +} + +static inline void ufstw_lu_update(struct ufstw_lu *tw) +{ + /* Flag */ + pm_runtime_get_sync(tw->ufsf->hba->dev); + 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->flush_enable)) + goto error_put; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->flush_during_hibern_enter)) + goto error_put; + + /* Attribute */ + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_FLUSH_STATUS, + &tw->flush_status)) + goto error_put; + + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_AVAIL_BUF_SIZE, + &tw->available_buffer_size)) + goto error_put; + + ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + &tw->lifetime_est); +error_put: + pm_runtime_put_sync(tw->ufsf->hba->dev); +} + +static int ufstw_lu_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufstw_lu *tw; + int ret = 0; + + if (lun == TW_LU_SHARED) + tw = ufsf->tw_lup[0]; + else + tw = ufsf->tw_lup[lun]; + + tw->ufsf = ufsf; + spin_lock_init(&tw->lifetime_lock); + + ufstw_lu_update(tw); + + ret = ufstw_check_lifetime_not_guarantee(tw); + if (ret) + goto err_out; + + ufstw_print_lu_flag_attr(tw); + + tw->stat_write_sec = 0; + + ufstw_init_lu_jobs(tw); + +#if defined(CONFIG_UFSTW_BOOT_ENABLED) + pm_runtime_get_sync(ufsf->hba->dev); + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, &tw->tw_enable); + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->flush_during_hibern_enter); + pm_runtime_put_sync(ufsf->hba->dev); +#endif + ret = ufstw_create_sysfs(ufsf, tw); + if (ret) + ERR_MSG("create sysfs failed"); +err_out: + return ret; +} + +void ufstw_init(struct ufsf_feature *ufsf) +{ + int lun, ret = 0; + unsigned int tw_enabled_lun = 0; + + INFO_MSG("init start.. tw_state (%d)", ufstw_get_state(ufsf)); + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + if (!ufsf->tw_lup[0]) { + ERR_MSG("tw_lup memory allocation failed"); + goto out; + } + BUG_ON(ufsf->tw_lup[0]->lun != TW_LU_SHARED); + + ret = ufstw_lu_init(ufsf, TW_LU_SHARED); + if (ret) + goto out_free_mem; + + INFO_MSG("ufstw_lu[shared] working"); + tw_enabled_lun++; + } else { + seq_scan_lu(lun) { + if (!ufsf->tw_lup[lun]) + continue; + + ret = ufstw_lu_init(ufsf, lun); + if (ret) + goto out_free_mem; + + INFO_MSG("ufstw_lu[%d] working", lun); + tw_enabled_lun++; + } + + if (tw_enabled_lun > ufsf->tw_dev_info.tw_number_lu) { + ERR_MSG("lu count mismatched"); + goto out_free_mem; + } + } + + if (tw_enabled_lun == 0) { + ERR_MSG("tw_enabled_lun count zero"); + goto out_free_mem; + } + + ufstw_set_state(ufsf, TW_PRESENT); + return; +out_free_mem: + seq_scan_lu(lun) { + kfree(ufsf->tw_lup[lun]); + ufsf->tw_lup[lun] = NULL; + } +out: + ERR_MSG("Turbo write intialization failed"); + + ufstw_set_state(ufsf, TW_FAILED); +} + +static inline void ufstw_remove_sysfs(struct ufstw_lu *tw) +{ + int ret; + + ret = kobject_uevent(&tw->kobj, KOBJ_REMOVE); + INFO_MSG("kobject removed (%d)", ret); + kobject_del(&tw->kobj); +} + +void ufstw_remove(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + + dump_stack(); + INFO_MSG("start release"); + + ufstw_set_state(ufsf, TW_FAILED); + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + INFO_MSG("ufstw_lu[shared] %p", tw); + ufsf->tw_lup[0] = NULL; + ufstw_cancel_lu_jobs(tw); + ufstw_remove_sysfs(tw); + kfree(tw); + } else { + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + INFO_MSG("ufstw_lu[%d] %p", lun, tw); + + if (!tw) + continue; + ufsf->tw_lup[lun] = NULL; + ufstw_cancel_lu_jobs(tw); + ufstw_remove_sysfs(tw); + kfree(tw); + } + } + + INFO_MSG("end release"); +} + +static void ufstw_reset_query_handling(struct ufstw_lu *tw) +{ + int ret; + + if (tw->tw_enable) { + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable); + if (ret) + tw->tw_enable = false; + } + + if (tw->flush_enable) { + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->flush_enable); + if (ret) + tw->flush_enable = false; + } + + if (tw->flush_during_hibern_enter) { + ret = ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->flush_during_hibern_enter); + if (ret) + tw->flush_during_hibern_enter = false; + } +} + +void ufstw_reset_host(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + + if (ufstw_is_not_present(ufsf)) + return; + + ufstw_set_state(ufsf, TW_RESET); + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + + INFO_MSG("ufstw_lu[shared] cancel jobs"); + ufstw_cancel_lu_jobs(tw); + } else { + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + INFO_MSG("ufstw_lu[%d] cancel jobs", lun); + ufstw_cancel_lu_jobs(tw); + } + } +} + +void ufstw_reset(struct ufsf_feature *ufsf, bool resume) +{ + struct ufstw_lu *tw; + int lun; + + INFO_MSG("ufstw reset start. reason: %s", + resume ? "resume" : "reset"); + if (ufstw_get_state(ufsf) != TW_RESET) { + ERR_MSG("tw_state error (%d)", ufstw_get_state(ufsf)); + return; + } + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + + INFO_MSG("ufstw_lu[shared] reset"); + ufstw_reset_query_handling(tw); + } else { + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + INFO_MSG("ufstw_lu[%d] reset", lun); + ufstw_reset_query_handling(tw); + } + } + + ufstw_set_state(ufsf, TW_PRESENT); + INFO_MSG("ufstw reset finish"); +} + +#define ufstw_sysfs_attr_show_func(_query, _name, _IDN, hex) \ +static ssize_t ufstw_sysfs_show_##_name(struct ufstw_lu *tw, char *buf) \ +{ \ + int ret; \ + \ + pm_runtime_get_sync(tw->ufsf->hba->dev); \ + if (ufstw_is_not_present(tw->ufsf)) { \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + return -ENODEV; \ + } \ + \ + ret = ufstw_read_lu_##_query(tw, _IDN, &tw->_name); \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + if (ret) \ + return -ENODEV; \ + \ + INFO_MSG("read "#_query" "#_name" %u (0x%X)", \ + tw->_name, tw->_name); \ + if (hex) \ + return snprintf(buf, PAGE_SIZE, "0x%.2X\n", tw->_name); \ + return snprintf(buf, PAGE_SIZE, "%u\n", tw->_name); \ +} + +#define ufstw_sysfs_attr_store_func(_name, _IDN) \ +static ssize_t ufstw_sysfs_store_##_name(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 == 0 || val == 1)) \ + return -EINVAL; \ + \ + INFO_MSG("val %lu", val); \ + pm_runtime_get_sync(tw->ufsf->hba->dev); \ + if (ufstw_is_not_present(tw->ufsf)) { \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + return -ENODEV; \ + } \ + \ + if (val) { \ + if (ufstw_set_lu_flag(tw, _IDN, &tw->_name)) \ + ret = -ENODEV; \ + } else { \ + if (ufstw_clear_lu_flag(tw, _IDN, &tw->_name)) \ + ret = -ENODEV; \ + } \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + \ + INFO_MSG(#_name " query success"); \ + return ret; \ +} + +ufstw_sysfs_attr_show_func(flag, tw_enable, QUERY_FLAG_IDN_TW_EN, 0); +ufstw_sysfs_attr_store_func(tw_enable, QUERY_FLAG_IDN_TW_EN); +ufstw_sysfs_attr_show_func(flag, flush_enable, + QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, 0); +ufstw_sysfs_attr_store_func(flush_enable, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN); +ufstw_sysfs_attr_show_func(flag, flush_during_hibern_enter, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, 0); +ufstw_sysfs_attr_store_func(flush_during_hibern_enter, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN); + +ufstw_sysfs_attr_show_func(attr, flush_status, + QUERY_ATTR_IDN_TW_FLUSH_STATUS, 0); +ufstw_sysfs_attr_show_func(attr, available_buffer_size, + QUERY_ATTR_IDN_TW_AVAIL_BUF_SIZE, 0); +ufstw_sysfs_attr_show_func(attr, lifetime_est, + QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, 1); +ufstw_sysfs_attr_show_func(attr, curr_buffer_size, + QUERY_ATTR_IDN_TW_CURR_BUF_SIZE, 0); + +#define ufstw_sysfs_attr_ro(_name) __ATTR(_name, 0444,\ + ufstw_sysfs_show_##_name, NULL) +#define ufstw_sysfs_attr_rw(_name) __ATTR(_name, 0644,\ + ufstw_sysfs_show_##_name, \ + ufstw_sysfs_store_##_name) + +static struct ufstw_sysfs_entry ufstw_sysfs_entries[] = { + /* Flag */ + ufstw_sysfs_attr_rw(tw_enable), + ufstw_sysfs_attr_rw(flush_enable), + ufstw_sysfs_attr_rw(flush_during_hibern_enter), + /* Attribute */ + ufstw_sysfs_attr_ro(flush_status), + ufstw_sysfs_attr_ro(available_buffer_size), + ufstw_sysfs_attr_ro(lifetime_est), + ufstw_sysfs_attr_ro(curr_buffer_size), + __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; + + mutex_lock(&tw->sysfs_lock); + error = entry->show(tw, page); + mutex_unlock(&tw->sysfs_lock); + 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; + + mutex_lock(&tw->sysfs_lock); + error = entry->store(tw, page, length); + mutex_unlock(&tw->sysfs_lock); + 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; + char lun_str[20] = { 0 }; + + tw->sysfs_entries = ufstw_sysfs_entries; + + kobject_init(&tw->kobj, &ufstw_ktype); + mutex_init(&tw->sysfs_lock); + + if (tw->lun == TW_LU_SHARED) { + snprintf(lun_str, 6, "ufstw"); + INFO_MSG("ufstw creates sysfs ufstw-shared"); + } else { + snprintf(lun_str, 10, "ufstw_lu%d", tw->lun); + INFO_MSG("ufstw creates sysfs ufstw_lu%d", tw->lun); + } + + err = kobject_add(&tw->kobj, kobject_get(&dev->kobj), lun_str); + if (!err) { + for (entry = tw->sysfs_entries; entry->attr.name != NULL; + entry++) { + if (tw->lun == TW_LU_SHARED) + INFO_MSG("ufstw-shared sysfs attr creates: %s", + entry->attr.name); + else + INFO_MSG("ufstw_lu(%d) sysfs attr creates: %s", + tw->lun, entry->attr.name); + + err = sysfs_create_file(&tw->kobj, &entry->attr); + if (err) { + ERR_MSG("create entry(%s) failed", + entry->attr.name); + goto kobj_del; + } + } + kobject_uevent(&tw->kobj, KOBJ_ADD); + } else { + ERR_MSG("kobject_add failed"); + } + + return err; +kobj_del: + err = kobject_uevent(&tw->kobj, KOBJ_REMOVE); + INFO_MSG("kobject removed (%d)", err); + kobject_del(&tw->kobj); + return -EINVAL; +} diff --git a/drivers/scsi/ufs/ufs31/ufstw.h b/drivers/scsi/ufs/ufs31/ufstw.h new file mode 100644 index 000000000000..5cdd7617ad8d --- /dev/null +++ b/drivers/scsi/ufs/ufs31/ufstw.h @@ -0,0 +1,126 @@ +/* + * 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 0x0110 +#define UFSTW_DD_VER 0x010300 +#define UFSTW_DD_VER_POST "" + +#define UFSTW_LIFETIME_SECT 2097152 /* 1GB */ +#define UFSTW_MAX_LIFETIME_VALUE 0x0B +#define MASK_UFSTW_LIFETIME_NOT_GUARANTEE 0x80 +#define UFS_FEATURE_SUPPORT_TW_BIT 0x100 + +#define TW_LU_SHARED -1 + +enum UFSTW_STATE { + TW_NEED_INIT = 0, + TW_PRESENT = 1, + TW_RESET = -3, + TW_FAILED = -4 +}; + +enum { + TW_BUF_TYPE_LU = 0, + TW_BUF_TYPE_SHARED, +}; + +struct ufstw_dev_info { + /* from Device Descriptor */ + u16 tw_ver; + u32 tw_shared_buf_alloc_units; + 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; + + bool tw_enable; + bool flush_enable; + bool flush_during_hibern_enter; + + unsigned int flush_status; + unsigned int available_buffer_size; + unsigned int curr_buffer_size; + + unsigned int lifetime_est; + spinlock_t lifetime_lock; + u32 stat_write_sec; + struct work_struct tw_lifetime_work; + + /* 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; + +int ufstw_get_state(struct ufsf_feature *ufsf); +void ufstw_set_state(struct ufsf_feature *ufsf, int state); +void ufstw_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf); +void ufstw_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf); +void ufstw_alloc_lu(struct ufsf_feature *ufsf, int lun, u8 *lu_buf); + +void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufstw_init(struct ufsf_feature *ufsf); +void ufstw_remove(struct ufsf_feature *ufsf); +void ufstw_reset_host(struct ufsf_feature *ufsf); +void ufstw_reset(struct ufsf_feature *ufsf, bool resume); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 230611e9e146..b8fe4cc44b4b 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,11 @@ 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); -static void ufshcd_hold_all(struct ufs_hba *hba); +#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 +673,11 @@ 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); +#if defined(CONFIG_UFSFEATURE) +void ufshcd_hold_all(struct ufs_hba *hba); +#else static void ufshcd_hold_all(struct ufs_hba *hba); -static void ufshcd_release_all(struct ufs_hba *hba); +#endif 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, @@ -1745,7 +1929,7 @@ out: static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) { - #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ + #define DOORBELL_CLR_TOUT_US (10000 * 1000) /* 10 sec */ int ret = 0; /* * make sure that there are no outstanding requests when @@ -2659,7 +2843,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; @@ -2950,8 +3138,8 @@ static void ufshcd_init_hibern8(struct ufs_hba *hba) return; if (ufshcd_is_auto_hibern8_supported(hba)) { - /* Set the default auto-hiberate idle timer value to 1 ms */ - hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 1) | + /* Set the default auto-hiberate idle timer value to 5 ms */ + hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 5) | FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); h8->state = AUTO_HIBERN8; /* @@ -2995,13 +3183,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); @@ -3218,8 +3414,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); @@ -3300,7 +3498,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; @@ -3338,7 +3540,7 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) lrbp->utr_descriptor_ptr->prd_table_length = 0; } - return ufshcd_map_sg_crypto(hba, lrbp); + return 0; } /** @@ -3571,7 +3773,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; @@ -3583,6 +3789,16 @@ 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) +#if defined(UFS3V1) + ufsf_change_read10_debug_lun(&hba->ufsf, lrbp); + ufsf_prep_fn(&hba->ufsf, lrbp); +#elif defined(UFS3V0) + ufsf_hpb_change_lun(&hba->ufsf, lrbp); + ufsf_tw_prep_fn(&hba->ufsf, lrbp); + ufsf_hpb_prep_fn(&hba->ufsf, lrbp); +#endif +#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); @@ -3674,6 +3890,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); @@ -3784,6 +4007,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); @@ -3836,9 +4080,28 @@ 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; +#if defined(UFS3V1) + atomic64_inc(&hba->ufsf.hpb_lup[add_lrbp->lun]->pre_req_cnt); +#elif defined(UFS3V0) + atomic64_inc(&hba->ufsf.ufshpb_lup[add_lrbp->lun]->pre_req_cnt); +#endif + } +#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); @@ -3855,6 +4118,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; @@ -3990,8 +4265,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; } @@ -4043,8 +4320,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; @@ -4618,6 +4900,127 @@ 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(struct ufs_hba *hba, 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 if (capacity == 0x1DCF0000) { //256GB sandisk + return "256G"; + } else { + dev_err(hba->dev, "%s:ufs capacity %llx\n", __func__, capacity); + 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); +#if defined(UFS3V1) + if (hba->ufsf.hpb_lup[0]) + strlcat(ufs_product_id, "_H", sizeof(ufs_product_id)); +#elif defined(UFS3V0) + if (hba->ufsf.ufshpb_lup[0]) + strlcat(ufs_product_id, "_H", sizeof(ufs_product_id)); +#endif + 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(hba, 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 @@ -5210,6 +5613,7 @@ more_wait: 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); @@ -5688,9 +6092,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, @@ -6200,6 +6606,20 @@ 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) +#if defined(UFS3V1) + ufsf_slave_configure(&hba->ufsf, sdev); +#elif defined(UFS3V0) + 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 +#endif blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); @@ -6372,6 +6792,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 */ @@ -6424,8 +6849,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; } @@ -6536,6 +6963,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 || @@ -6931,6 +7365,15 @@ out: static bool ufshcd_wb_sup(struct ufs_hba *hba) { +#if defined(CONFIG_UFSTW) +#if defined(UFS3V1) + if (is_samsung_ufs(hba)) + return false; +#elif defined(UFS3V0) + return false; +#endif +#endif + return ((hba->dev_info.d_ext_ufs_feature_sup & UFS_DEV_WRITE_BOOSTER_SUP) && (hba->dev_info.b_wb_buffer_type @@ -7116,6 +7559,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) && defined(UFS3V0) + ufsf_tw_ee_handler(&hba->ufsf); +#endif out: ufshcd_scsi_unblock_requests(hba); /* @@ -7248,6 +7694,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; @@ -7907,6 +8354,14 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) out: hba->req_abort_count = 0; if (!err) { +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) + ufsf_reset_lu(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_reset_lu(&hba->ufsf); + ufsf_tw_reset_lu(&hba->ufsf); +#endif +#endif err = SUCCESS; } else { dev_err(hba->dev, "%s: failed with err %d\n", __func__, err); @@ -8127,6 +8582,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) int err; unsigned long flags; +#if defined(CONFIG_UFSFEATURE) && defined(UFS3V1) + ufsf_reset_host(&hba->ufsf); +#endif /* * Stop the host controller and complete the requests * cleared by h/w @@ -8135,6 +8593,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) && defined(UFS3V0) + 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); @@ -9198,6 +9660,15 @@ reinit: } scsi_scan_host(hba->host); +#if defined(CONFIG_UFSFEATURE) + ufsf_device_check(hba); +#if defined(UFS3V1) + ufsf_init(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_init(&hba->ufsf); + ufsf_tw_init(&hba->ufsf); +#endif +#endif pm_runtime_put_sync(hba->dev); } @@ -9217,9 +9688,22 @@ out: ufshcd_hba_exit(hba); } +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) + ufsf_reset(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_reset(&hba->ufsf); + ufsf_tw_reset(&hba->ufsf); +#endif +#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; } @@ -9314,6 +9798,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: @@ -10257,9 +10749,14 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba) ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); } else if (!ufshcd_is_ufs_dev_active(hba)) { if (!hba->dev_info.keep_vcc_on) +#if !defined(CONFIG_UFSTW) ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false); +#endif + if (!ufshcd_is_link_active(hba)) { +#if !defined(CONFIG_UFSTW) ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq); +#endif ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); } } @@ -10369,6 +10866,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state = UIC_LINK_OFF_STATE; } +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_suspend(&hba->ufsf); +#if defined(UFS3V0) + ufsf_tw_suspend(&hba->ufsf); +#endif +#endif + ret = ufshcd_crypto_suspend(hba, pm_op); if (ret) goto out; @@ -10502,6 +11006,14 @@ enable_gating: hba->hibern8_on_idle.is_suspended = false; hba->clk_gating.is_suspended = false; ufshcd_release_all(hba); +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) + ufsf_resume(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_resume(&hba->ufsf); + ufsf_tw_resume(&hba->ufsf); +#endif +#endif ufshcd_crypto_resume(hba, pm_op); out: hba->pm_op_in_progress = 0; @@ -10626,6 +11138,15 @@ 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) +#if defined(UFS3V1) + ufsf_resume(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_resume(&hba->ufsf); + ufsf_tw_resume(&hba->ufsf); +#endif +#endif + /* Set Auto-Hibernate timer if supported */ ufshcd_set_auto_hibern8_timer(hba); @@ -10905,6 +11426,14 @@ EXPORT_SYMBOL(ufshcd_shutdown); */ void ufshcd_remove(struct ufs_hba *hba) { +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) + ufsf_remove(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_release(&hba->ufsf); + ufsf_tw_release(&hba->ufsf); +#endif +#endif ufs_sysfs_remove_nodes(hba->dev); scsi_remove_host(hba->host); /* disable interrupts */ @@ -10921,6 +11450,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); @@ -11198,9 +11728,18 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_cmd_log_init(hba); +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) + ufsf_set_init_state(&hba->ufsf); +#elif defined(UFS3V0) + ufsf_hpb_set_init_state(&hba->ufsf); + ufsf_tw_set_init_state(&hba->ufsf); +#endif +#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 2a6b30d8e663..fc405ad73ffe 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -76,6 +76,14 @@ #include "ufs.h" #include "ufshci.h" +#if defined(CONFIG_UFSFEATURE) +#if defined(UFS3V1) +#include "ufs31/ufsfeature.h" +#elif defined(UFS3V0) +#include "ufs30/ufsfeature.h" +#endif +#endif + #define UFSHCD "ufshcd" #define UFSHCD_DRIVER_VERSION "0.3" @@ -231,6 +239,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 }; /** @@ -1104,6 +1116,10 @@ struct ufs_hba { bool force_g4; bool wb_enabled; +#if defined(CONFIG_UFSFEATURE) + struct ufsf_feature ufsf; +#endif + #ifdef CONFIG_SCSI_UFS_CRYPTO /* crypto */ union ufs_crypto_capabilities crypto_capabilities; @@ -1377,6 +1393,15 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, u32 size, bool ascii); +#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 int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba, bool no_sched); diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c index 7430bb271b2d..87d2cfc33472 100644 --- a/drivers/soc/qcom/msm_performance.c +++ b/drivers/soc/qcom/msm_performance.c @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif /* * Sched will provide the data for every 20ms window, @@ -63,6 +66,9 @@ static int set_cpu_min_freq(const char *buf, const struct kernel_param *kp) struct cpu_status *i_cpu_stats; struct cpufreq_policy policy; cpumask_var_t limit_mask; +#ifdef CONFIG_CONTROL_CENTER + bool boost_on_big_hint = false; +#endif while ((cp = strpbrk(cp + 1, " :"))) ntokens++; @@ -102,6 +108,11 @@ static int set_cpu_min_freq(const char *buf, const struct kernel_param *kp) if (cpufreq_get_policy(&policy, i)) continue; +#ifdef CONFIG_CONTROL_CENTER + if (i == 7 && policy.max == i_cpu_stats->min) + boost_on_big_hint = true; +#endif + if (cpu_online(i) && (policy.min != i_cpu_stats->min)) cpufreq_update_policy(i); @@ -110,6 +121,23 @@ static int set_cpu_min_freq(const char *buf, const struct kernel_param *kp) } put_online_cpus(); +#ifdef CONFIG_CONTROL_CENTER + if (boost_on_big_hint) { + struct cc_command cc; + + /* init default turbo boost command */ + memset(&cc, 0, sizeof(struct cc_command)); + cc.pid = current->pid; + cc.prio = CC_PRIO_HIGH; + cc.period_us = 2 * 1000 * 1000; /* us */ + cc.group = CC_CTL_GROUP_SYSTEM; + cc.response = 0; + cc.status = 0; + cc.type = CC_CTL_TYPE_PERIOD_NONBLOCK; + cc.category = CC_CTL_CATEGORY_TB_PLACE_BOOST; + cc_tsk_process(&cc); + } +#endif return 0; } diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c index da575edfb04d..ebf9cfe774f2 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 6bc411d40477..f8d2bec8b5fd 100644 --- a/drivers/soc/qcom/qmp-debugfs-client.c +++ b/drivers/soc/qcom/qmp-debugfs-client.c @@ -26,6 +26,95 @@ static struct mbox_client *cl; static DEFINE_MUTEX(qmp_debugfs_mutex); +#ifdef CONFIG_CONTROL_CENTER +#define DDR_CONFIG_SIZE 13 +#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: 0}", 30 }, + { "{class:ddr, res:fixed, val: 200}", 32 }, + { "{class:ddr, res:fixed, val: 300}", 32 }, + { "{class:ddr, res:fixed, val: 451}", 32 }, + { "{class:ddr, res:fixed, val: 547}", 32 }, + { "{class:ddr, res:fixed, val: 681}", 32 }, + { "{class:ddr, res:fixed, val: 768}", 32 }, + { "{class:ddr, res:fixed, val: 1017}", 33 }, + { "{class:ddr, res:fixed, val: 1353}", 33 }, + { "{class:ddr, res:fixed, val: 1555}", 33 }, + { "{class:ddr, res:fixed, val: 1804}", 33 }, + { "{class:ddr, res:fixed, val: 2092}", 33 }, + { "{class:ddr, res:fixed, val: 2736}", 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: + case 100: + target = 0; + break; + case 200: + target = 1; + break; + case 300: + target = 2; + break; + case 451: + target = 3; + break; + case 547: + target = 4; + break; + case 681: + target = 5; + break; + case 768: + target = 6; + break; + case 1017: + target = 7; + break; + case 1353: + target = 8; + break; + case 1555: + target = 9; + break; + case 1804: + target = 10; + break; + case 2092: + target = 11; + break; + case 2736: + target = 12; + 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 079ec84890fc..3c493aed9975 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 @@ -56,6 +60,8 @@ struct msm_rpm_stats_data { }; +struct dentry *debugfs_root; + struct msm_rpmstats_kobj_attr { struct kobject *kobj; struct kobj_attribute ka; @@ -77,6 +83,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 (2*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 AOP without entering PC"); + } + } else if (get_time_in_sec(arch_counter_get_cntvct()) - time > TIMEOUT_FOR_DUMP) + time = 0; + } else if (get_time_in_sec(arch_counter_get_cntvct()) - time > TIMEOUT_FOR_DUMP) + time = 0; + } else { + time = get_time_in_sec(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 +207,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 +245,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; - } - - rpms_ka = kzalloc(sizeof(*rpms_ka), GFP_KERNEL); - if (!rpms_ka) { - kobject_put(rpmstats_kobj); - ret = -ENOMEM; - goto fail; - } - - rpms_ka->kobj = rpmstats_kobj; - - 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; - - ret = sysfs_create_file(rpmstats_kobj, &rpms_ka->ka.attr); - platform_set_drvdata(pdev, rpms_ka); - -fail: - return ret; + return single_open(file, rpmh_stats_show, inode->i_private); } +#endif + +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 +}; + +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 +}; + +static ssize_t stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct msm_rpmstats_private_data prvdata; + + 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 +379,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 daffd30d37e2..a4ae157fb1c8 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -462,8 +462,9 @@ 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); + //too much log here,remove it + //pr_info_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 d4418baaa1ab..9e41fb959526 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,113 @@ 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); + panic("Because %s without entering PC", 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; + + 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; + } + } + + return true; +} + +static int rpmh_master_stats_show(struct seq_file *s, void *data) +{ + int i = 0; + size_t size = 0; struct msm_rpmh_master_stats *record = NULL; mutex_lock(&rpmh_stats_mutex); /* First Read APSS master stats */ - length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE, - &apss_master_stats, "APSS"); + msm_rpmh_master_stats_print_data(s, &apss_master_stats, + "APSS"); /* Read SMEM data written by other 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].smem_id, &size); + 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 +262,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; + int i = 0; + size_t size = 0; + struct msm_rpmh_master_stats *record = NULL; + char stats_buf[1024]; + uint64_t temp_accumulated_duration = 0; - prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL); - if (!prvdata) - return ret; + mutex_lock(&rpmh_stats_mutex); - rpmh_master_stats_kobj = kobject_create_and_add( - "rpmh_stats", - power_kobj); - if (!rpmh_master_stats_kobj) - return ret; + /* First Read APSS master stats */ - prvdata->kobj = rpmh_master_stats_kobj; + temp_accumulated_duration = apss_master_stats.accumulated_duration; - 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; + if (apss_master_stats.last_entered > apss_master_stats.last_exited) + temp_accumulated_duration += + (arch_counter_get_cntvct() + - apss_master_stats.last_entered); - ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr); - if (ret) { - pr_err("sysfs_create_file failed\n"); - goto fail_sysfs; + 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 72c1a5fe6138..99d51032a495 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 3da5a978d9f6..e584f35ba73c 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,22 @@ static int init_service_locator(void) SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID); - rc = wait_for_completion_interruptible_timeout( + /*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) { + /*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/spss_utils.c b/drivers/soc/qcom/spss_utils.c index e3ab1c4b28e5..9092afcf1225 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 e979abd14ee3..57da71502b2b 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) @@ -817,6 +818,9 @@ static void log_failure_reason(const struct pil_tz_data *d) strlcpy(reason, smem_reason, min(size, (size_t)MAX_SSR_REASON_LEN)); pr_err("%s subsystem failure reason: %s.\n", name, reason); + function_name = parse_function_builtin_return_address( + (unsigned long)__builtin_return_address(0)); + save_dump_reason_to_smem(reason, function_name); } static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop) @@ -975,7 +979,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 +990,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 69f7aa599ee0..0787405abd2d 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -35,6 +35,9 @@ #include #include "peripheral-loader.h" +#include +#include +#include #define DISABLE_SSR 0x9889deed /* If set to 0x9889deed, call to subsystem_restart_dev() returns immediately */ @@ -194,6 +197,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 +257,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 +390,45 @@ void subsys_default_online(struct subsys_device *dev) } EXPORT_SYMBOL(subsys_default_online); + +void subsys_send_uevent_notify(struct subsys_desc *desc) +{ + 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", dev->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,11 @@ static int subsystem_shutdown(struct subsys_device *dev, void *data) subsys_set_state(dev, SUBSYS_OFFLINE); disable_all_irqs(dev); + // Send esoc0 uevent in mdm_get_restart_reason() + // Send wlan uevent in cnss_pci_collect_dump_info() + if ((strcmp(name, "esoc0") != 0) && (strcmp(name, "wlan") != 0)) + subsys_send_uevent_notify(dev->desc); + return 0; } @@ -831,6 +882,112 @@ 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[][10] = { + "ipa_fws", + "ipa_uc", + "wlan", + "esoc0", + "adsp", + "cdsp", + "venus", + "spss", + "cvpss", + "npu", + "slpi", + "a650_zap" + }; + int i = 0; + char temp[4] = {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; @@ -932,9 +1089,9 @@ int wait_for_shutdown_ack(struct subsys_desc *desc) return 0; ret = wait_for_completion_timeout(&dev->shutdown_ack, - msecs_to_jiffies(10000)); + msecs_to_jiffies(5000)); if (!ret) { - pr_err("[%s]: Timed out waiting for shutdown ack\n", + pr_err("[%s]: Timed out (5000ms) waiting for shutdown ack\n", desc->name); return -ETIMEDOUT; } @@ -1251,9 +1408,21 @@ int subsystem_restart_dev(struct subsys_device *dev) __subsystem_restart_dev(dev); break; case RESET_SOC: + /*small board absent ignore reset soc*/ + if (get_small_board_1_absent() == 1 || get_small_board_2_absent() == 1) { + pr_warn("subsys-restart: small board absent restart request for %s\n", name); + __subsystem_restart_dev(dev); + } else if (!oem_get_modemdump_mode() && !(strcmp(name, "esoc0")) && oem_get_download_mode()) { + pr_err("%s ssr state=%d\n", name, get_esoc_ssr_state()); + if (get_esoc_ssr_state() == 0) { + set_esoc_ssr_state(1); + __subsystem_restart_dev(dev); + } + } else { __pm_stay_awake(dev->ssr_wlock); schedule_work(&dev->device_restart_work); - return 0; + } + return 0; default: panic("subsys-restart: Unknown restart level!\n"); break; @@ -1910,6 +2079,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) @@ -2002,6 +2172,7 @@ static int __init subsys_restart_init(void) if (ret) goto err_soc; + init_restart_level_all_node(); return 0; err_soc: diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index d844c3144e02..fb057f8c2bb0 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,10 @@ 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 +195,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 da143d3e49fb..cbfc7243ff82 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 5b86c5fbbe41..29bda5d0908b 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/Makefile b/drivers/thermal/Makefile index 2162f70e829c..3dfede47a5ea 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 000000000000..f23776c1e969 --- /dev/null +++ b/drivers/thermal/horae_shell_temp.c @@ -0,0 +1,209 @@ +// 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 + +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; + } + 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/of-thermal.c b/drivers/thermal/of-thermal.c index 2f74de504146..3dddcc2aa81a 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,10 @@ 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/bcl_soc.c b/drivers/thermal/qcom/bcl_soc.c index a375f43ee2a5..fe937b40dd23 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 @@ eval_exit: 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,6 +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); + INIT_WORK(&bcl_perph->bcl_usb_work, bcl_usb_process); bcl_perph->psy_nb.notifier_call = battery_supply_callback; ret = power_supply_reg_notifier(&bcl_perph->psy_nb); if (ret < 0) { diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 5ba494e5fddc..bad8e6be627c 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -34,6 +35,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 +57,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 +1331,32 @@ 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_zone49/ and /sys/class/thermal/thermal_zone79 + */ + 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 +1653,101 @@ 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; + + 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); + 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 +1779,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/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index ea78f9048e1f..8020545b9424 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -285,7 +285,13 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) } else { pr_err("%s: tsens controller got reset\n", __func__); - BUG(); + tmdev->trdy_fail_ctr++; + if (tmdev->trdy_fail_ctr >= 50) { + if (tmdev->ops->dbg) + tmdev->ops->dbg(tmdev, 0, + TSENS_DBG_LOG_BUS_ID_DATA, NULL); + BUG(); + } } return -EAGAIN; } diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index c1f18d2fcda4..87c58161b0bb 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; @@ -3437,12 +3472,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 +3529,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 +3544,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 +3561,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 60c2ec4daf75..4f89cd26ffd8 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1804,6 +1804,12 @@ static int autosuspend_check(struct usb_device *udev) * or else their drivers don't support autosuspend * and so they are permanently active. */ + 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 ed408f40017f..b1cb69f985b6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4466,6 +4466,9 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if (hub) connect_type = hub->ports[udev->portnum - 1]->connect_type; + 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; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 089764528308..2b8934ae099f 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -47,6 +47,8 @@ #include "debug.h" #include "xhci.h" +#include "../pd/usbpd.h" + #define SDP_CONNETION_CHECK_TIME 10000 /* in ms */ /* time out to wait for USB cable status notification (in ms)*/ @@ -71,6 +73,7 @@ #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) +#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 +122,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 +358,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 +2285,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 +2313,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 +2665,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 +2723,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); @@ -3638,6 +3658,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; @@ -3668,7 +3699,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 @@ -4123,6 +4154,15 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, udev->dev.parent->parent == &dwc->xhci->dev) { if (event == USB_DEVICE_ADD && udev->actconfig) { if (!dwc3_msm_is_ss_rhport_connected(mdwc)) { + /* + * controller may wakeup ss phy during hs data + * transfers or doorbell rings. Power down the + * ss phy to avoid turning on pipe clock during + * these wake-ups. + */ + mdwc->ss_phy->flags |= PHY_WAKEUP_WA_EN; + usb_phy_powerdown(mdwc->ss_phy); + /* * Core clock rate can be reduced only if root * hub SS port is not enabled/connected. @@ -4138,6 +4178,8 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, mdwc->max_rh_port_speed = USB_SPEED_SUPER; } } else { + usb_phy_powerup(mdwc->ss_phy); + mdwc->ss_phy->flags &= ~PHY_WAKEUP_WA_EN; /* set rate back to default core clk rate */ clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); dev_dbg(mdwc->dev, "set core clk rate %ld\n", @@ -4555,6 +4597,8 @@ set_prop: return 0; } +#define DWC3_DCTL 0xc704 +#define DWC3_DCTL_RUN_STOP BIT(31) /** * dwc3_otg_sm_work - workqueue function. @@ -4571,6 +4615,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) int ret = 0; unsigned long delay = 0; const char *state; + u32 reg; if (mdwc->dwc3) dwc = platform_get_drvdata(mdwc->dwc3); @@ -4640,9 +4685,19 @@ static void dwc3_otg_sm_work(struct work_struct *w) atomic_read(&mdwc->dev->power.usage_count)); dwc3_otg_start_peripheral(mdwc, 1); mdwc->drd_state = DRD_STATE_PERIPHERAL; + if (!dwc->softconnect && + get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP) { + dbg_event(0xFF, "cdp pullup dp", 0); + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_RUN_STOP; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + break; + } + work = 1; } else { - dwc3_msm_gadget_vbus_draw(mdwc, 0); + //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 1b70b8da2a72..fae77e71666e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -27,6 +27,22 @@ #include "debug.h" #include "gadget.h" #include "io.h" +#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 +857,10 @@ 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: + 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 e9ea382b36f3..f29709db9779 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2107,6 +2107,8 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, return 0; } +#define DWC3_SOFT_RESET_TIMEOUT 10 /* 10 msec */ + /** * dwc3_device_core_soft_reset - Issues device core soft reset * @dwc: pointer to our context structure @@ -2151,6 +2153,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg, reg1; u32 timeout = 1500; + ktime_t start, diff; dbg_event(0xFF, "run_stop", is_on); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -2162,7 +2165,24 @@ 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; + start = ktime_get(); + /* issue device SoftReset */ + dwc3_writel(dwc->regs, DWC3_DCTL, + reg | DWC3_DCTL_CSFTRST); + do { + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (!(reg & DWC3_DCTL_CSFTRST)) + break; + diff = ktime_sub(ktime_get(), start); + /* poll for max. 10ms */ + if (ktime_to_ms(diff) > DWC3_SOFT_RESET_TIMEOUT) { + printk_ratelimited(KERN_ERR + "%s:core Reset Timed Out\n", __func__); + break; + } + cpu_relax(); + } while (true); dwc3_event_buffers_setup(dwc); __dwc3_gadget_start(dwc); @@ -3423,8 +3443,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 +3855,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 +4027,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/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index 8124af33b738..d4e75bf95c28 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); - ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep); - if (ret) - return ret; + if (!alt) { + usb_ep_disable(audio->in_ep); + return 0; + } + + ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep); + 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 511d46db6049..228fa47ef97d 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -643,12 +643,19 @@ 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)); - - if (unlikely(ffs->state == FFS_CLOSING)) + if (atomic_read(&ffs->opened)) { + pr_err("ep0 is already opened!\n"); return -EBUSY; + } + + 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 8bce7ce0eaaa..42fd776ea724 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -228,6 +228,7 @@ /*------------------------------------------------------------------------*/ +#define PAGE_CACHE_SIZE PAGE_SIZE #define FSG_DRIVER_DESC "Mass Storage Function" #define FSG_DRIVER_VERSION "2009/09/11" @@ -1181,6 +1182,249 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) return 8; } +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 +1432,17 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) int start_track = common->cmnd[6]; u8 *buf = (u8 *)bh->buf; + 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; } + 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 +2180,23 @@ static int do_scsi_command(struct fsg_common *common) goto unknown_cmnd; common->data_size_from_cmnd = get_unaligned_be16(&common->cmnd[7]); + 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; + 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 +2479,6 @@ reset: } } - /* 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 +2490,6 @@ reset: 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]; @@ -2293,20 +2519,71 @@ reset: static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { + int rc; struct fsg_dev *fsg = fsg_from_func(f); /* 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 +3142,10 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, ? "File-CD Gadget" : "File-Stor Gadget"), i); +/* @BSP, 2020/04/04, 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 +3654,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 80ff811b6b1a..6023542725d8 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,18 @@ #define MAX_INST_NAME_LEN 40 #define MTP_MAX_FILE_SIZE 0xFFFFFFFFL +#define MTP_TX_BUFFER_BASE 0xAC300000 +#define MTP_RX_BUFFER_BASE 0xACB00000 +#define MTP_INTR_BUFFER_BASE 0xACD00000 + +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 +107,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 +121,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 +184,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 +424,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 +435,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 +550,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 +596,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 +637,11 @@ retry_tx_alloc: 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 +653,17 @@ retry_rx_alloc: 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 +766,11 @@ requeue_req: 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 +904,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 +1007,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; @@ -948,6 +1047,13 @@ static void receive_file_work(struct work_struct *data) r = -EIO; goto fail; } + 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); while (count > 0 || write_req) { if (count > 0) { /* queue a request */ @@ -1032,12 +1138,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) { struct usb_request *req = NULL; @@ -1053,12 +1169,15 @@ 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; + if (mtp_lock(&dev->ioctl_excl)) + return -EBUSY; if (copy_from_user(req->buf, (void __user *)event->data, length)) { mtp_req_put(dev, &dev->intr_idle, req); + mtp_unlock(&dev->ioctl_excl); return -EFAULT; } req->length = length; @@ -1066,6 +1185,7 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) if (ret) mtp_req_put(dev, &dev->intr_idle, req); + mtp_unlock(&dev->ioctl_excl); return ret; } @@ -1122,20 +1242,32 @@ 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. */ - queue_work(dev->wq, work); - /* wait for operation to complete */ - flush_workqueue(dev->wq); - fput(filp); - - /* read the result */ - smp_rmb(); + dev->xfer_result = 0; + if (dev->xfer_file_length) { + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); + if (mtp_receive_flag) { + mtp_receive_flag = false; + msm_cpuidle_set_sleep_disable(false); + } + /* read the result */ + smp_rmb(); + } ret = dev->xfer_result; + fput(filp); fail: spin_lock_irq(&dev->lock); @@ -1168,8 +1300,8 @@ static long mtp_ioctl(struct file *fp, unsigned int code, unsigned long value) ret = mtp_send_receive_ioctl(fp, code, &mfr); break; case MTP_SEND_EVENT: - if (mtp_lock(&dev->ioctl_excl)) - return -EBUSY; +// if (mtp_lock(&dev->ioctl_excl)) +// return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ @@ -1177,7 +1309,7 @@ static long mtp_ioctl(struct file *fp, unsigned int code, unsigned long value) ret = -EFAULT; else ret = mtp_send_event(dev, &event); - mtp_unlock(&dev->ioctl_excl); +// mtp_unlock(&dev->ioctl_excl); break; default: mtp_log("unknown ioctl code: %d\n", code); @@ -1237,8 +1369,8 @@ static long compat_mtp_ioctl(struct file *fp, unsigned int code, mfr.transaction_id = cmfr.transaction_id; ret = mtp_send_receive_ioctl(fp, cmd, &mfr); } else { - if (mtp_lock(&dev->ioctl_excl)) - return -EBUSY; +// if (mtp_lock(&dev->ioctl_excl)) +// return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ @@ -1250,7 +1382,7 @@ static long compat_mtp_ioctl(struct file *fp, unsigned int code, event.length = cevent.length; event.data = compat_ptr(cevent.data); ret = mtp_send_event(dev, &event); - mtp_unlock(&dev->ioctl_excl); +// mtp_unlock(&dev->ioctl_excl); } fail: return ret; @@ -1277,6 +1409,18 @@ static int mtp_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_release\n"); + 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); + } mtp_unlock(&_mtp_dev->open_excl); return 0; } @@ -1706,6 +1850,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 +1870,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 +1897,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 +2019,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 4e944c04be41..4c34c9a782f5 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -650,6 +650,7 @@ int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) goto out; } + 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-hub.c b/drivers/usb/host/xhci-hub.c index d32d7da231da..0980ef9ffac6 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-trace.h" @@ -942,6 +943,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, spin_lock_irqsave(&xhci->lock, *flags); if (time_left) { + usb_phy_powerdown(hcd->usb3_phy); slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); if (!slot_id) { @@ -1289,6 +1291,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Resume the port to U0 first */ xhci_set_link_state(xhci, ports[wIndex], XDEV_U0); + usb_phy_powerdown(hcd->usb3_phy); spin_unlock_irqrestore(&xhci->lock, flags); msleep(10); spin_lock_irqsave(&xhci->lock, flags); @@ -1313,6 +1316,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* unlock to execute stop endpoint commands */ spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); + usb_phy_powerup(hcd->usb3_phy); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, ports[wIndex], XDEV_U3); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 5a27091f2524..0aed1c2b28f3 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, 2020/03/25 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-plat.c b/drivers/usb/host/xhci-plat.c index f9c29020bd30..a51a5469c857 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -337,7 +337,8 @@ static int xhci_plat_probe(struct platform_device *pdev) if (device_property_read_u32(&pdev->dev, "usb-core-id", &xhci->core_id)) xhci->core_id = -EINVAL; - hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0); + hcd->usb_phy = devm_usb_get_phy_by_phandle(pdev->dev.parent, "usb-phy", + 0); if (IS_ERR(hcd->usb_phy)) { ret = PTR_ERR(hcd->usb_phy); if (ret == -EPROBE_DEFER) @@ -350,6 +351,16 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->skip_phy_initialization = 1; } + + hcd->usb3_phy = devm_usb_get_phy_by_phandle(pdev->dev.parent, "usb-phy", + 1); + if (IS_ERR(hcd->usb3_phy)) { + ret = PTR_ERR(hcd->usb3_phy); + if (ret == -EPROBE_DEFER) + goto put_usb3_hcd; + hcd->usb3_phy = NULL; + } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 20ea7f5cb044..097a140e0884 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2752,6 +2752,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) goto out; } + 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 3892106807af..7ba2de76d408 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -138,7 +138,9 @@ 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); + 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 +1045,19 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } + 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 6692263ae9d4..55a4cd4a481f 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -20,8 +22,14 @@ #include #include #include +#include #include "usbpd.h" +/* 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, PE_ERROR_RECOVERY, @@ -402,6 +410,8 @@ struct usbpd { bool peer_usb_comm; bool peer_pr_swap; bool peer_dr_swap; + bool oem_bypass; + bool periph_direct; u32 sink_caps[7]; int num_sink_caps; @@ -415,6 +425,7 @@ struct usbpd { int bat_voltage_max; enum power_supply_typec_mode typec_mode; + enum power_supply_type psy_type; enum power_supply_typec_power_role forced_pr; bool vbus_present; @@ -440,8 +451,14 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; + + int vbus_gpio; + int otg_en_gpio; + bool vbus_enabled; bool vconn_enabled; + bool is_otg_mode; + bool use_external_boost; u8 tx_msgid[SOPII_MSG + 1]; u8 rx_msgid[SOPII_MSG + 1]; @@ -478,6 +495,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[] = { @@ -1200,7 +1219,15 @@ static void phy_shutdown(struct usbpd *pd) } if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); + switch_to_otg_mode(false); + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } } @@ -1399,7 +1426,7 @@ 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; @@ -1414,19 +1441,6 @@ 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"); - - 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; - } - } - if (!pd->in_explicit_contract) break; @@ -1598,17 +1612,17 @@ 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) { - ret = pd_send_msg(pd, MSG_NOT_SUPPORTED, NULL, - 0, SOP_MSG); - if (ret) - usbpd_set_state(pd, PE_SEND_SOFT_RESET); - } else { +// 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); +// } else { usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK, SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0); - } +// } } break; @@ -1939,9 +1953,13 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; + 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 @@ -1958,6 +1976,14 @@ static void vconn_swap(struct usbpd *pd) } } +bool typec_is_otg_mode(void) +{ + if (pd_p != NULL) + return pd_p->is_otg_mode; + else + return false; +} + static int enable_vbus(struct usbpd *pd) { union power_supply_propval val = {0}; @@ -1980,18 +2006,30 @@ static int enable_vbus(struct usbpd *pd) if (count < 99) msleep(100); /* need to wait an additional tCCDebounce */ - if (!pd->vbus) { - pd->vbus = devm_regulator_get(pd->dev.parent, "vbus"); - if (IS_ERR(pd->vbus)) { - usbpd_err(&pd->dev, "Unable to get vbus\n"); - return -EAGAIN; + if (pd->use_external_boost) { + pd->is_otg_mode = true; + switch_to_otg_mode(true); + msleep(20); + gpio_set_value_cansleep(pd->vbus_gpio, 1); + msleep(100); + gpio_set_value_cansleep(pd->otg_en_gpio, 1); + pd->vbus_enabled = true; + } else { + if (!pd->vbus) { + pd->vbus = devm_regulator_get(pd->dev.parent, "vbus"); + if (IS_ERR(pd->vbus)) { + usbpd_err(&pd->dev, "Unable to get vbus\n"); + return -EAGAIN; + } + } + ret = regulator_enable(pd->vbus); + if (ret) { + usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); + } else { + pd->is_otg_mode = false; + pd->vbus_enabled = true; } } - ret = regulator_enable(pd->vbus); - if (ret) - usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); - else - pd->vbus_enabled = true; count = 10; /* @@ -2028,8 +2066,8 @@ 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; +// if (pd->spec_rev == USBPD_REV_30) +// return pd->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; return true; } @@ -2109,8 +2147,10 @@ static int usbpd_startup_common(struct usbpd *pd, phy_params->data_role = pd->current_dr; phy_params->power_role = pd->current_pr; + /* if (pd->vconn_enabled) phy_params->frame_filter_val |= FRAME_FILTER_EN_SOPI; + */ ret = pd_phy_open(phy_params); if (ret) { @@ -2319,15 +2359,19 @@ 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); + 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; } @@ -2546,8 +2590,17 @@ static void handle_state_src_transition_to_default(struct usbpd *pd, regulator_disable(pd->vconn); pd->vconn_enabled = false; - if (pd->vbus_enabled) - regulator_disable(pd->vbus); + if (pd->vbus_enabled) { + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); + switch_to_otg_mode(false); + } else { + regulator_disable(pd->vbus); + } + } + pd->is_otg_mode = false; pd->vbus_enabled = false; if (pd->current_dr != DR_DFP) { @@ -3254,7 +3307,15 @@ static void handle_state_prs_src_snk_transition_to_off(struct usbpd *pd, int ret; if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); + switch_to_otg_mode(false); + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } @@ -3451,7 +3512,15 @@ static void handle_disconnect(struct usbpd *pd) POWER_SUPPLY_PROP_PD_ACTIVE, &val); if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); + switch_to_otg_mode(false); + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } @@ -3678,8 +3747,12 @@ static int usbpd_process_typec_mode(struct usbpd *pd, typec_mode == POWER_SUPPLY_TYPEC_SINK ? "" : " (powered)"); - if (pd->current_pr == PR_SRC) + 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; @@ -3725,9 +3798,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) ret); return ret; } + 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 +3814,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 +3859,17 @@ 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, + 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); @@ -4623,6 +4708,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; @@ -4641,10 +4727,41 @@ struct usbpd *usbpd_create(struct device *parent) if (ret) goto free_pd; + pd->use_external_boost = of_property_read_bool(parent->of_node, "otg-use_external_boost"); + if (pd->use_external_boost) { + usbpd_info(&pd->dev, "wkcs: otg use external boost\n"); + pd->vbus_gpio = of_get_named_gpio(parent->of_node, "vbus-gpio", 0); + if (!gpio_is_valid(pd->vbus_gpio)) { + usbpd_err(&pd->dev, "wkcs: can't find vbus-gpio\n"); + goto del_pd; + } + ret = devm_gpio_request_one(&pd->dev, pd->vbus_gpio, GPIOF_OUT_INIT_LOW, + "vbus-gpio"); + if (ret) { + usbpd_err(&pd->dev, "wkcs: can't request vbus gpio %d", pd->vbus_gpio); + goto del_pd; + } + pd->otg_en_gpio = of_get_named_gpio(parent->of_node, "otg_en-gpio", 0); + if (!gpio_is_valid(pd->otg_en_gpio)) { + usbpd_err(&pd->dev, "wkcs: can't find otg_en-gpio\n"); + goto free_vbus_gpio; + } + ret = devm_gpio_request_one(&pd->dev, pd->otg_en_gpio, GPIOF_OUT_INIT_LOW, + "otg_en-gpio"); + if (ret) { + usbpd_err(&pd->dev, "wkcs: can't request vbus gpio %d", pd->otg_en_gpio); + goto free_vbus_gpio; + } + } + pd->is_otg_mode = false; + pd->wq = alloc_ordered_workqueue("usbpd_wq", WQ_FREEZABLE | WQ_HIGHPRI); if (!pd->wq) { ret = -ENOMEM; - goto del_pd; + if (pd->use_external_boost) + goto free_otg_en_gpio; + else + goto del_pd; } INIT_WORK(&pd->sm_work, usbpd_sm); INIT_WORK(&pd->start_periph_work, start_usb_peripheral_work); @@ -4767,6 +4884,8 @@ struct usbpd *usbpd_create(struct device *parent) } } + pd->oem_bypass = true; + pd->periph_direct = false; pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); @@ -4793,6 +4912,13 @@ put_psy: power_supply_put(pd->usb_psy); destroy_wq: destroy_workqueue(pd->wq); +free_otg_en_gpio: + if (pd->use_external_boost && gpio_is_valid(pd->otg_en_gpio)) + devm_gpio_free(&pd->dev, pd->otg_en_gpio); +free_vbus_gpio: + if (pd->use_external_boost && gpio_is_valid(pd->vbus_gpio)) + devm_gpio_free(&pd->dev, pd->vbus_gpio); + del_pd: device_del(&pd->dev); free_pd: diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index ffc7350d6850..9786bcc70602 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -83,6 +83,11 @@ #define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */ #define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */ +/* Add to tune USB2.0 eye diagram */ +#define USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1 0x70 +unsigned int USB2_phy_tune1; +module_param(USB2_phy_tune1, uint, 0644); +MODULE_PARM_DESC(USB2_phy_tune1, "QUSB PHY v2 TUNE1"); struct msm_hsphy { struct usb_phy phy; void __iomem *base; @@ -388,6 +393,17 @@ 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_tune1) { + pr_err("%s(): (modparam) USB2_phy_tune1 val:0x%02x\n", + __func__, USB2_phy_tune1); + writel_relaxed(USB2_phy_tune1, + phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1); + } + + pr_err("USB2_tune1_register_val:0x%02x\n", + readl_relaxed(phy->base + + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1)); if (phy->pre_emphasis) { u8 val = TXPREEMPAMPTUNE0(phy->pre_emphasis) & diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 33a47180c211..9361254cad41 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -801,6 +801,32 @@ static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy, return 0; } +static int msm_ssphy_qmp_powerup(struct usb_phy *uphy, bool powerup) +{ + struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, + phy); + u8 reg = powerup ? 1 : 0; + u8 temp; + + if (!(uphy->flags & PHY_WAKEUP_WA_EN)) + return 0; + + temp = readl_relaxed(phy->base + + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + + if (temp == powerup) + return 0; + + writel_relaxed(reg, + phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + temp = readl_relaxed(phy->base + + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + + dev_dbg(uphy->dev, "P3 powerup:%x\n", temp); + + return 0; +} + static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; @@ -1120,6 +1146,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; + phy->phy.powerup = msm_ssphy_qmp_powerup; if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) phy->phy.reset = msm_ssphy_qmp_dp_combo_reset; diff --git a/fs/Kconfig b/fs/Kconfig index b8d003f02b76..ae25bc959176 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 9d1caea038f6..f638fb45a45e 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -132,3 +132,10 @@ obj-y += exofs/ # Multiple modules obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ +obj-$(CONFIG_EXFAT_FS) += exfat/ +# filter instantnoodle, instantnoodlep ... +ifeq ($(filter instantnoodle%, $(OEM_TARGET_PRODUCT)),) +KBUILD_CFLAGS += -DUFS3V1 +else +KBUILD_CFLAGS += -DUFS3V0 +endif diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index c1f897808397..be0bda5746bf 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -482,12 +482,14 @@ static void put_crypt_info(struct fscrypt_info *ci) FSCRYPT_MODE_PRIVATE) { fscrypt_destroy_prepared_key(&ci->ci_key); } else { + crypto_free_skcipher(ci->ci_key.tfm); #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT if (ci->ci_key.blk_key) kzfree(ci->ci_key.blk_key); #endif } } + key = ci->ci_master_key; if (key) { struct fscrypt_master_key *mk = key->payload.data[0]; diff --git a/fs/direct-io.c b/fs/direct-io.c index 715e699af7b5..9c50ba0c1134 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 4760c2b7ea84..2d7799af1036 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1817,10 +1817,15 @@ fetch_events: } spin_unlock_irq(&ep->wq.lock); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 + current->in_epoll = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ spin_lock_irq(&ep->wq.lock); } diff --git a/fs/exec.c b/fs/exec.c index aa9d20cbd689..d5b165628b3a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -71,6 +71,9 @@ #include "internal.h" #include +#ifdef CONFIG_IM +#include +#endif int suid_dumpable = 0; @@ -1240,6 +1243,9 @@ 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)); +#ifdef CONFIG_IM + im_wmi(tsk); +#endif task_unlock(tsk); perf_event_comm(tsk, exec); } @@ -1699,6 +1705,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 100755 index 000000000000..78b32aa2ca19 --- /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 100755 index 000000000000..d159169d1050 --- /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 100755 index 000000000000..711ed87f991b --- /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 100755 index 000000000000..b4ac4b073f00 --- /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 100755 index 000000000000..77a47cdcaf81 --- /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 100755 index 000000000000..4e3ef07b36ec --- /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 100755 index 000000000000..32b29f0dd8d9 --- /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 100755 index 000000000000..84bdf612a1e6 --- /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 100755 index 000000000000..b0672dd073fc --- /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 100755 index 000000000000..4f482c7b28cc --- /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 100755 index 000000000000..eaccfd84e9f9 --- /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 100755 index 000000000000..3363b591caeb --- /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 100755 index 000000000000..4130102e3739 --- /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 100755 index 000000000000..540e31681d04 --- /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 100755 index 000000000000..33c6525e449b --- /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 100755 index 000000000000..7c4d3c2d1980 --- /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 100755 index 000000000000..52d05c7007d3 --- /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 100755 index 000000000000..65da07aff547 --- /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 100755 index 000000000000..53b0e39397fa --- /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 100755 index 000000000000..a48b3d05a7c4 --- /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 100755 index 000000000000..bc516d762e90 --- /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 100755 index 000000000000..0b23445f343a --- /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 100755 index 000000000000..b6dd7897ab6e --- /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 100755 index 000000000000..51893f1b6ab7 --- /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 100755 index 000000000000..916811e3d31e --- /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 100755 index 000000000000..3807f37caacb --- /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 100755 index 000000000000..77e6c074928b --- /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 2dd1bbca241c..f1c9afc8c0f7 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -102,6 +102,15 @@ config F2FS_FAULT_INJECTION If unsure, say N. +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. config F2FS_FS_COMPRESSION bool "F2FS compression feature" depends on F2FS_FS diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 49c18affde5d..1bde6b5e24a8 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -14,6 +14,10 @@ #include #include +#if defined(CONFIG_UFSTW) && defined(UFS3V0) +#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) && defined(UFS3V0) + 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 @@ stop: f2fs_update_time(sbi, CP_TIME); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); out: +#if defined(CONFIG_UFSTW) && defined(UFS3V0) + 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 16b12d11a9d8..c0e3d990662f 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,7 +2586,20 @@ got_it: 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 9c02abdd27cb..6f19be7260f5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -205,6 +205,10 @@ 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 +#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 +318,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 +328,9 @@ enum { DPOLICY_FORCE, DPOLICY_FSTRIM, DPOLICY_UMOUNT, +#ifdef CONFIG_F2FS_OF2FS + DPOLICY_ODISCARD, +#endif MAX_DPOLICY, }; @@ -336,6 +346,9 @@ 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 + bool io_busy; /* interrupt by user io */ +#endif }; struct discard_cmd_control { @@ -346,6 +359,10 @@ 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 + 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 +1495,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 +1529,17 @@ struct f2fs_sb_info { __u32 s_chksum_seed; struct workqueue_struct *post_read_wq; /* post read workqueue */ + +#ifdef CONFIG_F2FS_OF2FS + bool is_frag; /* urgent gc flag */ + unsigned long last_frag_check; /* last urgent check jiffies */ + atomic_t need_ssr_gc; /* ssr gc count */ + bool gc_opt_enable; + + struct list_head sbi_list; + unsigned long last_wp_odc_jiffies; + bool odiscard_already_run; +#endif }; struct f2fs_private_dio { @@ -3623,6 +3655,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 +4056,51 @@ static inline bool is_journalled_quota(struct f2fs_sb_info *sbi) return false; } +#ifdef CONFIG_F2FS_OF2FS +#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 ce3819090f12..e3dc25a9fa21 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -22,6 +22,10 @@ #include #include +#if defined(CONFIG_UFSTW) && defined(UFS3V0) +#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) && defined(UFS3V0) + 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 @@ go_write: 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 @@ go_write: clear_inode_flag(inode, FI_UPDATE_WRITE); goto out; } +#if defined(CONFIG_UFSTW) && defined(UFS3V0) + 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 @@ sync_nodes: 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 @@ flush_out: } f2fs_update_time(sbi, REQ_TIME); out: +#if defined(CONFIG_UFSTW) && defined(UFS3V0) + 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 db8725d473b5..14a7ef7ae401 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -20,6 +20,166 @@ #include "gc.h" #include +#ifdef CONFIG_F2FS_OF2FS +#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 +191,15 @@ static int gc_thread_func(void *data) set_freezable(); do { +#ifdef CONFIG_F2FS_OF2FS + 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 +207,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 +217,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 +229,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 +255,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 +264,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 +275,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 +290,7 @@ next: sb_end_write(sbi->sb); } while (!kthread_should_stop()); + f2fs_printk(sbi, KERN_INFO "Debug:%s:gc_opt_return", __func__); return 0; } @@ -136,8 +313,13 @@ 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 + 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 +694,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 +713,17 @@ next_step: 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 +763,10 @@ next_step: 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 +1196,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 +1218,20 @@ next_step: * 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 +1340,10 @@ next_step: 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 +1351,13 @@ next_step: 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 +1387,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 +1464,19 @@ freed: 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 +1510,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 +1569,9 @@ gc_more: 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 +1618,18 @@ stop: 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 +1644,11 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES; +#ifdef CONFIG_F2FS_OF2FS + 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 bbac9d3787bd..0d7a775491d9 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -25,6 +25,10 @@ struct f2fs_gc_kthread { struct task_struct *f2fs_gc_task; wait_queue_head_t gc_wait_queue_head; +#ifdef CONFIG_F2FS_OF2FS + wait_queue_head_t fggc_wait_queue_head; +#endif + /* for gc sleep time */ unsigned int urgent_sleep_time; @@ -41,6 +45,12 @@ struct gc_inode_list { struct radix_tree_root iroot; }; +#ifdef CONFIG_F2FS_OF2FS +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 1fb2ef09ff70..7ca9a3ab899b 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 469990ab1e62..275f7c5b629f 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -15,6 +15,12 @@ #include #include #include +#ifdef CONFIG_F2FS_OF2FS +#include + +int f2fs_trim_status; +int f2fs_odiscard_enable = true; +#endif #include "f2fs.h" #include "segment.h" @@ -29,6 +35,15 @@ 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 +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 +198,34 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi) SM_I(sbi)->min_ssr_sections + reserved_sections(sbi)); } + +#ifdef CONFIG_F2FS_OF2FS +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 +524,118 @@ int f2fs_commit_inmem_pages(struct inode *inode) return err; } +#ifdef CONFIG_F2FS_OF2FS +#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 +654,19 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) if (!f2fs_is_checkpoint_ready(sbi)) return; +#ifdef CONFIG_F2FS_OF2FS + 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) @@ -903,11 +1063,21 @@ 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 +1122,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 +1144,14 @@ 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 + 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 +1190,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 +1223,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 +1382,10 @@ submit: * 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 +1635,10 @@ 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 + if (f2fs_odiscard_enable) + dpolicy->io_busy = true; +#endif io_interrupted = true; break; } @@ -1507,6 +1715,10 @@ retry: if (dpolicy->io_aware && i < dpolicy->io_aware_gran && !is_idle(sbi, DISCARD_TIME)) { io_interrupted = true; +#ifdef CONFIG_F2FS_OF2FS + if (f2fs_odiscard_enable) + dpolicy->io_busy = true; +#endif break; } @@ -1632,9 +1844,23 @@ 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 + 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 + 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 +1909,14 @@ 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 + 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 +1936,165 @@ 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 + 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 + 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 +2114,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 +2141,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 +3269,25 @@ 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 + 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 + 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 +3528,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 +3663,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 +3722,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 +5051,151 @@ void f2fs_destroy_segment_manager_caches(void) kmem_cache_destroy(discard_entry_slab); kmem_cache_destroy(inmem_entry_slab); } + +#ifdef CONFIG_F2FS_OF2FS +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 459dc3901a57..cf5e8e89538f 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -613,7 +613,11 @@ 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 +#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 ff8f15623a5f..9ed6e4e548ba 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,20 @@ #define CREATE_TRACE_POINTS #include + +#ifdef CONFIG_F2FS_OF2FS +#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 +229,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 +341,113 @@ static void init_once(void *foo) inode_init_once(&fi->vfs_inode); } +#ifdef CONFIG_F2FS_OF2FS +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 +1304,12 @@ static void f2fs_put_super(struct super_block *sb) int i; bool dropped; +#ifdef CONFIG_F2FS_OF2FS + 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 */ @@ -1605,7 +1767,9 @@ 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 set_opt(sbi, FLUSH_MERGE); +#endif set_opt(sbi, DISCARD); if (f2fs_sb_has_blkzoned(sbi)) set_opt_mode(sbi, F2FS_MOUNT_LFS); @@ -2643,6 +2807,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 +3164,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 +3363,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 +3379,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 +3557,16 @@ try_onemore: 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 */ @@ -3746,6 +3940,13 @@ reset_checkpoint: f2fs_update_time(sbi, CP_TIME); f2fs_update_time(sbi, REQ_TIME); clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); +#ifdef CONFIG_F2FS_OF2FS + 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 +4086,9 @@ static void destroy_inodecache(void) static int __init init_f2fs_fs(void) { int err; +#ifdef CONFIG_F2FS_OF2FS + struct timespec ts = {ODISCARD_WAKEUP_INTERVAL, 0}; +#endif if (PAGE_SIZE != F2FS_BLKSIZE) { printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n", @@ -3925,6 +4129,21 @@ static int __init init_f2fs_fs(void) err = f2fs_init_bio_entry_cache(); if (err) goto free_post_read; + +#ifdef CONFIG_F2FS_OF2FS + 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 + err = f2fs_init_bioset(); if (err) goto free_bio_enrty_cache; @@ -3956,6 +4175,17 @@ fail: static void __exit exit_f2fs_fs(void) { +#ifdef CONFIG_F2FS_OF2FS + 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 a97b37c16af4..38bb83fa1a5d 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -803,6 +803,147 @@ static int __maybe_unused victim_bits_seq_show(struct seq_file *seq, return 0; } +#ifdef CONFIG_F2FS_OF2FS +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, +}; + +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 +992,16 @@ 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 + 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 +1011,28 @@ 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 + 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 60da84a86dab..0d4c2c4a6bfa 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 24a6bc8b9bd8..eea95633e33a 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) @@ -572,10 +629,15 @@ 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; 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 +1349,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 +1394,23 @@ 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; + } + } + } + /* matches barrier in request_wait_answer() */ smp_mb__after_atomic(); if (test_bit(FR_INTERRUPTED, &req->flags)) @@ -1892,6 +1974,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 +2015,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 2c4ceb75482e..26a7e54a8175 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,6 +502,19 @@ 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 (err) goto out_free_ff; @@ -511,6 +527,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 3964325432ae..415cae8d2f18 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,15 +23,21 @@ 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; memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); if (!fc->atomic_o_trunc) inarg.flags &= ~O_TRUNC; + if (fc->writeback_cache) + inarg.flags &= ~O_APPEND; + args.in.h.opcode = opcode; args.in.h.nodeid = nodeid; args.in.numargs = 1; @@ -40,7 +47,13 @@ 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); + iname = inode_name(file_inode(file)); + args.iname = iname; + + ret = fuse_simple_request(fc, &args); + 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 @@ out: 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 3d53a17b1f64..27ec4f29754d 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 000000000000..b326ef9d798f --- /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 cb018315ecaf..420343ad9991 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 000000000000..ace991f86d2b --- /dev/null +++ b/fs/fuse/shortcircuit.c @@ -0,0 +1,206 @@ +// 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; +module_param(sct_mode, int, 0644); + +static char *__dentry_name(struct dentry *dentry, char *name) +{ + char *p = dentry_path_raw(dentry, name, PATH_MAX); + char *root; + size_t len; + + root = dentry->d_sb->s_fs_info; + len = strlen(root); + 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); + + strlcpy(name, root, PATH_MAX); + if (len > p - name) { + __putname(name); + return NULL; + } + + if (p > name + len) + strlcat(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_info("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/jbd2/commit.c b/fs/jbd2/commit.c index 4200a6fe9599..f4a4c6f77ae0 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -26,6 +26,10 @@ #include #include +#if defined(CONFIG_UFSTW) && defined(UFS3V0) +#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) && defined(UFS3V0) + bdev_set_turbo_write(journal->j_dev); +#endif /* * Now start flushing things to disk, in the order they appear @@ -1129,6 +1136,9 @@ restart_loop: write_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_done_commit); +#if defined(CONFIG_UFSTW) && defined(UFS3V0) + bdev_clear_turbo_write(journal->j_dev); +#endif /* * Calculate overall stats */ diff --git a/fs/namei.c b/fs/namei.c index 8492dc67fc3c..7fcf632848f1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -40,6 +40,9 @@ #include #include #include +#ifdef CONFIG_FSC +#include +#endif #include "internal.h" #include "mount.h" @@ -2433,12 +2436,25 @@ 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 +2462,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 +3829,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 +4824,12 @@ retry_deleg: 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 b14aef04ee01..2e8c0c7418af 100644 --- a/fs/open.c +++ b/fs/open.c @@ -31,6 +31,9 @@ #include #include #include +#ifdef CONFIG_FSC +#include +#endif #include "internal.h" @@ -863,6 +866,9 @@ cleanup_file: * the return value of d_splice_alias(), then the caller needs to perform dput() * on it after finish_open(). * + * On successful return @file is a fully instantiated open file. After this, if + * an error occurs in ->atomic_open(), it needs to clean up with fput(). + * * Returns zero on success or -errno if the open failed. */ int finish_open(struct file *file, struct dentry *dentry, @@ -1099,8 +1105,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 d4cd5235cbda..dfa3773e82d8 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,161 @@ static const struct file_operations proc_mem_operations = { .release = mem_release, }; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +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 +3500,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 +3536,305 @@ static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, } #endif /* CONFIG_LIVEPATCH */ +#ifdef CONFIG_IM +static int proc_im_flag(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ +#define IM_TAG_DESC_LEN (128) + char desc[IM_TAG_DESC_LEN] = {0}; + + im_to_str(task->im_flag, desc, IM_TAG_DESC_LEN); + desc[IM_TAG_DESC_LEN - 1] = '\0'; + seq_printf(m, "%d %s\n", task->im_flag, desc); + return 0; +} + +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}; + int c; + //struct inode *inode = file_inode(file); + //struct task_struct *p; + + 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; + } + + //p = get_proc_task(inode); + //if (!p) + // return -ESRCH; + + 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 (p->im_flag > 0) + 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); + } + + //put_task_struct(p); +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, +}; + /* * Thread groups */ @@ -3471,6 +3956,26 @@ 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 + REG("stuck_info", 0666, proc_stuck_trace_operations), +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ +#ifdef CONFIG_IM + ONE("im_flag", 0444, proc_im_flag), + REG("tb_ctl", 0666, proc_tbctl_operation), +#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 +#ifdef CONFIG_TPD + REG("tpd", 0666, proc_tpd_operation), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3865,6 +4370,19 @@ 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 + ONE("im_flag", 0444, proc_im_flag), + REG("tb_ctl", 0666, proc_tbctl_operation), +#endif +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + ONE("tli_info", 0444, proc_tli_info_show), +#endif +#ifdef CONFIG_TPD + REG("tpd", 0666, proc_tpd_operation), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index db189d59ce1e..0e3d7602b124 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -314,3 +314,9 @@ extern unsigned long task_statm(struct mm_struct *, unsigned long *, unsigned long *, unsigned long *, unsigned long *); extern void task_mem(struct seq_file *, struct mm_struct *); + +/* + * trace lost ram + */ +extern int read_fastrpc_usage(void); +extern int kgsl_pool_size_total(void); diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index f2dab6c2edb3..f9f439976778 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -20,6 +20,10 @@ #include #include #include "internal.h" +#include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) { @@ -63,12 +67,25 @@ static int meminfo_proc_show(struct seq_file *m, void *v) show_val_kb(m, "Buffers: ", i.bufferram); show_val_kb(m, "Cached: ", cached); show_val_kb(m, "SwapCached: ", total_swapcache_pages()); +#ifndef CONFIG_MEMPLUS show_val_kb(m, "Active: ", pages[LRU_ACTIVE_ANON] + pages[LRU_ACTIVE_FILE]); show_val_kb(m, "Inactive: ", pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]); show_val_kb(m, "Active(anon): ", pages[LRU_ACTIVE_ANON]); show_val_kb(m, "Inactive(anon): ", pages[LRU_INACTIVE_ANON]); +#else + show_val_kb(m, "Active: ", pages[LRU_ACTIVE_ANON] + + pages[LRU_ACTIVE_FILE] + + pages[LRU_ACTIVE_ANON_SWPCACHE]); + show_val_kb(m, "Inactive: ", pages[LRU_INACTIVE_ANON] + + pages[LRU_INACTIVE_FILE] + + pages[LRU_INACTIVE_ANON_SWPCACHE]); + show_val_kb(m, "Active(anon): ", pages[LRU_ACTIVE_ANON] + + pages[LRU_ACTIVE_ANON_SWPCACHE]); + show_val_kb(m, "Inactive(anon): ", pages[LRU_INACTIVE_ANON] + + pages[LRU_INACTIVE_ANON_SWPCACHE]); +#endif show_val_kb(m, "Active(file): ", pages[LRU_ACTIVE_FILE]); show_val_kb(m, "Inactive(file): ", pages[LRU_INACTIVE_FILE]); show_val_kb(m, "Unevictable: ", pages[LRU_UNEVICTABLE]); @@ -141,12 +158,22 @@ static int meminfo_proc_show(struct seq_file *m, void *v) show_val_kb(m, "ShmemPmdMapped: ", global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR); #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 #ifdef CONFIG_CMA show_val_kb(m, "CmaTotal: ", totalcma_pages); show_val_kb(m, "CmaFree: ", global_zone_page_state(NR_FREE_CMA_PAGES)); #endif + show_val_kb(m, "FastRPCUsed: ", read_fastrpc_usage()); + show_val_kb(m, "KgslCache: ", kgsl_pool_size_total()); + 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 535eda7857cf..549b8a6d872d 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 6f90d91a8733..d084a604a93d 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -369,6 +369,11 @@ 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 4bae3f4fe829..c74b20276095 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 bafbab2dd039..c32e0f4144ea 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,11 @@ 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 +391,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 +486,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 +709,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 +724,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 +754,7 @@ 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 +769,9 @@ 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 +782,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 +815,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 +869,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 +895,8 @@ fail_buf: 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 +918,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 +971,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 271c4c4cb760..40cdd36ef6a7 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,13 @@ 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 (err) @@ -350,6 +360,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 +461,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 +479,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 055daab8652a..e062673ed649 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,28 @@ int vfs_fsync(struct file *file, int datasync) } EXPORT_SYMBOL(vfs_fsync); +#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); } +#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/gen_headers_arm.bp b/gen_headers_arm.bp index b61129eaa953..77f142705fe3 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -94,6 +94,7 @@ gen_headers_out_arm = [ "drm/mga_drm.h", "drm/msm_drm.h", "drm/msm_drm_pp.h", + "drm/msm_drm_iris.h", "drm/nouveau_drm.h", "drm/omap_drm.h", "drm/qxl_drm.h", diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index d5c831841c06..517f752b5172 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -89,6 +89,7 @@ gen_headers_out_arm64 = [ "drm/mga_drm.h", "drm/msm_drm.h", "drm/msm_drm_pp.h", + "drm/msm_drm_iris.h", "drm/nouveau_drm.h", "drm/omap_drm.h", "drm/qxl_drm.h", diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 328f232f33ee..f9ccc5d927b1 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 efe246ce52bf..185d422cd315 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -39,6 +39,19 @@ enum { DRM_PANEL_BLANK_UNBLANK, /* panel: power off */ DRM_PANEL_BLANK_POWERDOWN, + /* panel power on for tp */ + 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, /* panel: low power mode */ DRM_PANEL_BLANK_LP, /* fps change */ diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index f3e6eed3e79c..ae77745f3d3c 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -306,7 +306,7 @@ void drm_err(const char *format, ...); * @fmt: printf() like format string. */ #define DRM_DEV_ERROR(dev, fmt, ...) \ - drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__) + drm_dev_printk(dev, KERN_ERR, "" fmt, ##__VA_ARGS__) #define DRM_ERROR(fmt, ...) \ drm_err(fmt, ##__VA_ARGS__) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c43316d3f5be..328da56020b7 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 */ @@ -646,8 +653,10 @@ struct request_queue { int bypass_depth; atomic_t mq_freeze_depth; +#if defined(CONFIG_BLK_DEV_BSG) bsg_job_fn *bsg_job_fn; struct bsg_class_device bsg_dev; +#endif #ifdef CONFIG_BLK_DEV_THROTTLING /* Throttle data */ @@ -676,6 +685,12 @@ struct request_queue { #define BLK_MAX_WRITE_HINTS 5 u64 write_hints[BLK_MAX_WRITE_HINTS]; + +#ifdef CONFIG_UFSTW +#if defined(UFS3V0) + bool turbo_write_dev; +#endif +#endif }; #define QUEUE_FLAG_QUEUED 0 /* uses generic tag queueing */ diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 8996c092568b..eadc548334b7 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 751506abe271..8e91f179abd3 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 12cec9cd4dc0..9271f1e09279 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -18,6 +18,7 @@ #include #include #include +#include /********************************************************************* * CPUFREQ INTERFACE * @@ -151,6 +152,21 @@ struct cpufreq_policy { /* For cpufreq driver's internal use */ void *driver_data; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 + +#ifdef CONFIG_PCCORE + unsigned int min_idx; +#endif }; /* Only for ACPI */ @@ -231,6 +247,7 @@ 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 */ +#define CPUFREQ_RELATION_OP 3 /* vendor customized frequency selection */ struct freq_attr { struct attribute attr; @@ -805,6 +822,8 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, struct cpufreq_frequency_table *pos; unsigned int freq; int idx, best = -1; + 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; @@ -822,9 +841,14 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, return idx; /* 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 { + if (target_freq - table[best].frequency > freq - target_freq) + return idx; + } return best; } @@ -839,6 +863,8 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, struct cpufreq_frequency_table *pos; unsigned int freq; int idx, best = -1; + 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; @@ -856,9 +882,14 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, return idx; /* Choose the closest freq */ - if (table[best].frequency - target_freq > target_freq - freq) - return idx; - + if (op_enable && op_mode == 1) { + if ((table[best].frequency - target_freq) < + ((table[best].frequency - freq) * (100 - get_op_limit()) / 100)) + return idx; + } else { + if (table[best].frequency - target_freq > target_freq - freq) + return idx; + } return best; } @@ -869,12 +900,31 @@ 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) { - target_freq = clamp_val(target_freq, policy->min, policy->max); + 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 +942,8 @@ 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); + 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 1dc351d8548b..d2262feb510f 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -410,5 +410,31 @@ do { \ *(_fsuid) = __cred->fsuid; \ *(_fsgid) = __cred->fsgid; \ } while(0) +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; +} + +#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 39898a1ee1cc..952c9ad7d726 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/esoc_client.h b/include/linux/esoc_client.h index a9a98015b727..891bfcf8c12c 100644 --- a/include/linux/esoc_client.h +++ b/include/linux/esoc_client.h @@ -8,6 +8,7 @@ #include #include #include +#include /* Flag values used with the power_on and power_off hooks */ #define ESOC_HOOK_MDM_CRASH 0x0001 /* In crash handling path */ @@ -71,4 +72,12 @@ static inline int esoc_unregister_client_hook(struct esoc_desc *desc, return -EIO; } #endif + +int ap_mdm_dump_once(void); +int set_esoc_ssr_state(int state); +int get_esoc_ssr_state(void); +int get_mdm_umount_state(void); +extern int oem_get_modemdump_mode(void); +extern bool oem_get_twice_modemdump_state(void); + #endif diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 21f5aa0b217f..85f007ae8f73 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -67,6 +67,9 @@ static inline bool try_to_freeze(void) return try_to_freeze_unsafe(); } +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 03db303ce975..8073e1af1381 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 f13272d84332..75687ce0e7ab 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/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index d80ab2b31d43..e3275fb48646 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -46,6 +46,56 @@ 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; + struct delayed_work press_pwr; +#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 +104,17 @@ 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, }; +#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 +124,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/mhi.h b/include/linux/mhi.h index 43bff5e409c1..629f61bd8bcb 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -16,6 +16,8 @@ struct mhi_sfr_info; #define REG_WRITE_QUEUE_LEN 1024 +#define SFR_BUF_SIZE 256 + /** * enum MHI_CB - MHI callback * @MHI_CB_IDLE: MHI entered idle state @@ -807,7 +809,7 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); * mhi_dump_sfr - Print SFR string from RDDM table. * @mhi_cntrl: MHI controller */ -void mhi_dump_sfr(struct mhi_controller *mhi_cntrl); +void mhi_dump_sfr(struct mhi_controller *mhi_cntrl, char *buf, size_t len); /** * mhi_get_remote_time - Get external modem time relative to host time diff --git a/include/linux/mm.h b/include/linux/mm.h index 678f36b58535..961dfe864ceb 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 10191c28fc04..46b395ad9918 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -77,6 +77,8 @@ static inline enum lru_list page_lru_base_type(struct page *page) { if (page_is_file_cache(page)) return LRU_INACTIVE_FILE; + if (PageSwapCache(page)) + return MEMPLUS_PAGE_LRU; return LRU_INACTIVE_ANON; } diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index f9fd5451e139..3d9d23b0dc0e 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -204,6 +204,9 @@ struct page { #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS int _last_cpupid; #endif +#if defined(CONFIG_MEMPLUS) && !(defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT)) + int8_t next_event; +#endif } _struct_page_alignment; #define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) @@ -291,6 +294,12 @@ struct vm_area_struct { struct mm_struct *vm_mm; /* The address space we belong to. */ pgprot_t vm_page_prot; /* Access permissions of this VMA. */ unsigned long vm_flags; /* Flags, see mm.h. */ +#ifdef CONFIG_VM_FRAGMENT_MONITOR + unsigned long rb_glfragment_gap; +#endif +#ifdef CONFIG_MEMPLUS + unsigned int memplus_flags; +#endif /* * For areas with an address space and backing store, @@ -510,6 +519,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 ad855211d81e..5841aa26893d 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 @@ -140,6 +143,10 @@ enum zone_stat_item { NR_ZONE_INACTIVE_ANON = NR_ZONE_LRU_BASE, NR_ZONE_ACTIVE_ANON, NR_ZONE_INACTIVE_FILE, +#ifdef CONFIG_MEMPLUS + NR_ZONE_INACTIVE_ANON_SWAPCACHE, + NR_ZONE_ACTIVE_ANON_SWAPCACHE, +#endif NR_ZONE_ACTIVE_FILE, NR_ZONE_UNEVICTABLE, NR_ZONE_WRITE_PENDING, /* Count of dirty, writeback and unstable pages */ @@ -153,6 +160,12 @@ enum zone_stat_item { NR_BOUNCE, #if IS_ENABLED(CONFIG_ZSMALLOC) NR_ZSPAGES, /* allocated in zsmalloc */ +#endif +#ifdef CONFIG_DEFRAG + NR_FREE_DEFRAG_POOL, +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO + NR_IONCACHE_PAGES, #endif NR_FREE_CMA_PAGES, NR_VM_ZONE_STAT_ITEMS }; @@ -163,6 +176,10 @@ enum node_stat_item { NR_ACTIVE_ANON, /* " " " " " */ NR_INACTIVE_FILE, /* " " " " " */ NR_ACTIVE_FILE, /* " " " " " */ +#ifdef CONFIG_MEMPLUS + NR_INACTIVE_ANON_SWAPCACHE, /* " " " " " */ + NR_ACTIVE_ANON_SWAPCACHE, /* " " " " " */ +#endif NR_UNEVICTABLE, /* " " " " " */ NR_SLAB_RECLAIMABLE, NR_SLAB_UNRECLAIMABLE, @@ -211,13 +228,22 @@ enum lru_list { LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE, LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE, LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE, +#ifdef CONFIG_MEMPLUS + LRU_INACTIVE_ANON_SWPCACHE, + LRU_ACTIVE_ANON_SWPCACHE, +#endif LRU_UNEVICTABLE, NR_LRU_LISTS }; #define for_each_lru(lru) for (lru = 0; lru < NR_LRU_LISTS; lru++) +#ifdef CONFIG_MEMPLUS +#define for_each_evictable_lru(lru) \ + for (lru = 0; lru <= LRU_ACTIVE_ANON_SWPCACHE; lru++) +#else #define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++) +#endif static inline int is_file_lru(enum lru_list lru) { @@ -226,7 +252,12 @@ static inline int is_file_lru(enum lru_list lru) static inline int is_active_lru(enum lru_list lru) { +#ifdef CONFIG_MEMPLUS + return (lru == LRU_ACTIVE_ANON || + lru == LRU_ACTIVE_FILE || lru == LRU_ACTIVE_ANON_SWPCACHE); +#else return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE); +#endif } struct zone_reclaim_stat { @@ -256,7 +287,14 @@ struct lruvec { /* Mask used at gathering information at once (see memcontrol.c) */ #define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE)) +#ifdef CONFIG_MEMPLUS +#define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | \ + BIT(LRU_ACTIVE_ANON) | \ + BIT(LRU_INACTIVE_ANON_SWPCACHE) | \ + BIT(LRU_ACTIVE_ANON_SWPCACHE)) +#else #define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON)) +#endif #define LRU_ALL ((1 << NR_LRU_LISTS) - 1) /* Isolate unmapped file */ diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h new file mode 100644 index 000000000000..6a90e1c5de67 --- /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 100755 index 000000000000..650a39432e08 --- /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 260c4421d3c0..9f8c1c35292e 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_MEMPLUS + PG_willneed, #endif __NR_PAGEFLAGS, @@ -324,6 +327,11 @@ PAGEFLAG(Reclaim, reclaim, PF_NO_TAIL) PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) +#ifdef CONFIG_MEMPLUS +PAGEFLAG(Willneed, willneed, PF_HEAD) +__CLEARPAGEFLAG(Willneed, willneed, PF_HEAD) +#endif + #ifdef CONFIG_HIGHMEM /* * Must use a macro here due to header dependency issues. page_zone() is not @@ -343,8 +351,16 @@ static __always_inline int PageSwapCache(struct page *page) return PageSwapBacked(page) && test_bit(PG_swapcache, &page->flags); } -SETPAGEFLAG(SwapCache, swapcache, PF_NO_TAIL) -CLEARPAGEFLAG(SwapCache, swapcache, PF_NO_TAIL) +#include +static __always_inline void ClearPageSwapCache(struct page *page) +{ + memplus_move_swapcache_to_anon_lru(page); +} + +static __always_inline void SetPageSwapCache(struct page *page) +{ + memplus_move_anon_to_swapcache_lru(page); +} #else PAGEFLAG_FALSE(SwapCache) #endif diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index e01df4271585..4ddaca3c0728 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -35,6 +35,9 @@ enum page_ext_flags { */ struct page_ext { unsigned long flags; +#if defined(CONFIG_MEMPLUS) && defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + int8_t next_event; +#endif }; extern void pgdat_page_ext_init(struct pglist_data *pgdat); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 58952fa01f1c..e3a5348d003e 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 e22de69dcd98..1c43634b8dc1 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, - + /* 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, + 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, /* 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 6e6a25220c56..2389c9acc7b0 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 7f3b376c691f..302571212c15 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -163,6 +163,28 @@ enum { enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, + 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, @@ -255,6 +277,10 @@ 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_APSD_NOT_DONE, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_RESISTANCE_ID, /* in Ohms */ @@ -361,6 +387,14 @@ enum power_supply_property { POWER_SUPPLY_PROP_CP_ILIM, POWER_SUPPLY_PROP_IRQ_STATUS, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, + POWER_SUPPLY_PROP_CP_DISABLE_CUR_SENS, + POWER_SUPPLY_PROP_WIRELESS_MODE, + POWER_SUPPLY_PROP_WIRELESS_TYPE, + 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_ICON_DELAY, POWER_SUPPLY_PROP_FG_TYPE, POWER_SUPPLY_PROP_CHARGER_STATUS, /* Local extensions of type int64_t */ @@ -375,6 +409,22 @@ enum power_supply_property { * MODEL_NAME and SERIAL_NUMBER. Don't add below SERIAL_NUMBER. */ POWER_SUPPLY_PROP_SERIAL_NUMBER, + + 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, + +/* @bsp, 2020/03/22 No need to show in sysfs */ + POWER_SUPPLY_PROP_VBATDET, }; enum power_supply_type { @@ -402,6 +452,10 @@ 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 */ + POWER_SUPPLY_TYPE_DASH, + POWER_SUPPLY_WIRELESS_TYPE_BPP, + POWER_SUPPLY_WIRELESS_TYPE_EPP, + POWER_SUPPLY_WIRELESS_TYPE_FAST, }; enum power_supply_usb_type { @@ -450,6 +504,7 @@ enum power_supply_typec_power_role { enum power_supply_notifier_events { PSY_EVENT_PROP_CHANGED, + PSY_EVENT_PROP_OTG_CHECK, }; union power_supply_propval { diff --git a/include/linux/printk.h b/include/linux/printk.h index cf3eccfe1543..cc7a671ed71f 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 de9093d6e660..2cf2341e180e 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 e6d226464838..bed90ebd4b8c 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/sched.h b/include/linux/sched.h index e9045ee71bca..e9e78782969b 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; @@ -132,6 +136,20 @@ enum fps { FPS120 = 120, }; +#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 /* @@ -223,6 +241,63 @@ enum fps { } while (0) #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +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 @@ -534,6 +609,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; @@ -826,6 +904,15 @@ struct task_struct { /* Per task flags (PF_*), defined further below: */ unsigned int flags; unsigned int ptrace; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + u64 rtstart_time; + u64 rtend_time; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + + int compensate_need; + + unsigned int kill_flag; + struct timespec ttu; #ifdef CONFIG_SMP struct llist_node wake_entry; @@ -1221,6 +1308,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; @@ -1470,13 +1562,96 @@ 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 + 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_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; +#endif + +#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; @@ -1488,6 +1663,12 @@ struct task_struct { */ }; +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; @@ -1723,6 +1904,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); } @@ -1742,6 +1928,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) @@ -1793,6 +1985,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); @@ -2213,4 +2410,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 b71b42aecb40..0df7d21a2038 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 e9d4e389aed9..cb37b33458f4 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/signal.h b/include/linux/sched/signal.h index 660d78c9af6c..4ef5775a6e6c 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -223,6 +223,12 @@ struct signal_struct { * oom */ bool oom_flag_origin; +#ifdef CONFIG_MEMPLUS + spinlock_t reclaim_state_lock; + unsigned long reclaim_timeout; + int swapin_should_readahead_m; + int memplus_type; +#endif short oom_score_adj; /* OOM kill score adjustment */ short oom_score_adj_min; /* OOM kill score adjustment min value. * Only settable by CAP_SYS_RESOURCE. */ diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 21d24612f9aa..59ec977fc0f1 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 83302aa822f7..7fa79196ee4a 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -449,11 +449,20 @@ extern bool has_usable_swap(void); /* Swap 50% full? Release swapcache more aggressively.. */ static inline bool vm_swap_full(void) { + /* + * don't bother replace any swapcache only entries + */ + if (__memplus_enabled()) + return false; + return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages; } static inline long get_nr_swap_pages(void) { + if (__memplus_enabled()) + return 0; + return atomic_long_read(&nr_swap_pages); } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 03444cd87c3f..8552d4343e86 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 8c71874e8485..ced77534931b 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -36,6 +36,16 @@ struct sysrq_key_op { int enable_mask; }; +extern int panic_flush_device_cache(int timeout); +extern int oem_get_download_mode(void); +extern bool oem_get_twice_modemdump_state(void); +extern int oem_get_modemdump_mode(void); + +#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 733ab62ae141..1688c2bdd21b 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 a5a3cfc3c2fa..b9a9becf794b 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 000000000000..c0248727fb68 --- /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 b0542cd11aeb..a54c52c76f7d 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -55,6 +55,8 @@ static inline gid_t __kgid_val(kgid_t gid) #define GLOBAL_ROOT_UID KUIDT_INIT(0) #define GLOBAL_ROOT_GID KGIDT_INIT(0) +#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/hcd.h b/include/linux/usb/hcd.h index a11715133ba3..37870a14bb18 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -103,6 +103,7 @@ struct usb_hcd { * other external phys should be software-transparent */ struct usb_phy *usb_phy; + struct usb_phy *usb3_phy; struct usb_phy_roothub *phy_roothub; /* Flags that need to be manipulated atomically because they can diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index b863726c7c5b..af76890832cb 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -26,6 +26,7 @@ #define PHY_HSFS_MODE BIT(8) #define PHY_LS_MODE BIT(9) #define PHY_USB_DP_CONCURRENT_MODE BIT(10) +#define PHY_WAKEUP_WA_EN BIT(14) #define EUD_SPOOF_DISCONNECT BIT(11) #define EUD_SPOOF_CONNECT BIT(12) #define PHY_SUS_OVERRIDE BIT(13) @@ -167,6 +168,7 @@ struct usb_phy { enum usb_device_speed speed); int (*notify_disconnect)(struct usb_phy *x, enum usb_device_speed speed); + int (*powerup)(struct usb_phy *x, bool start); /* * Charger detection method can be implemented if you need to @@ -365,6 +367,24 @@ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) return 0; } +static inline int +usb_phy_powerup(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, true); + else + return 0; +} + +static inline int +usb_phy_powerdown(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, false); + else + return 0; +} + static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h index beeafcf33c60..303aa0014ecf 100644 --- a/include/linux/vm_event_item.h +++ b/include/linux/vm_event_item.h @@ -113,6 +113,11 @@ enum vm_event_item { PGPGIN, PGPGOUT, PGPGOUTCLEAN, PSWPIN, PSWPOUT, #ifdef CONFIG_SPECULATIVE_PAGE_FAULT SPECULATIVE_PGFAULT_ANON, /* Speculative page fault field */ SPECULATIVE_PGFAULT_FILE, /* Speculative page fault field */ +#endif +#ifdef CONFIG_MEMPLUS + ANONFAULT, WPFAULT, SWAPFAULT, SWAPMAJFAULT, + PGCACHEMISS, READFAULT, COWFAULT, SHAREDFAULT, + FILEMAJFAULT, RETRYPAGE, SPECRETRY, #endif NR_VM_EVENT_ITEMS }; diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index f25cef84b41d..85535732e0b7 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -376,12 +376,35 @@ 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); + defrag_update_zone_free(migratetype, zone, nr_pages); } extern const char * const vmstat_text[]; diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 7a4f7c0e7a74..b6e99c32f786 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -238,5 +238,7 @@ extern int cnss_athdiag_write(struct device *dev, uint32_t offset, uint32_t mem_type, uint32_t data_len, uint8_t *input); extern int cnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode); - +/* WIFI MODIFICATION: */ +extern void cnss_set_fw_version(u32 version, u32 ext); +/* WIFI MODIFICATION: */ #endif /* _NET_CNSS2_H */ diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 8026c2386988..5007eaba207d 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -113,7 +113,9 @@ struct net { #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) struct netns_ieee802154_lowpan ieee802154_lowpan; #endif +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) struct netns_sctp sctp; +#endif #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) struct netns_dccp dccp; #endif diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index f45141bdbb83..b08055fdd6c0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -19,6 +19,9 @@ #include #include +/* WIFI MODIFICATION */ +#include +/* WIFI MODIFICATION */ #include #include #include @@ -35,6 +38,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 { @@ -87,6 +93,23 @@ struct nf_conn { /* 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/netns/netfilter.h b/include/net/netns/netfilter.h index 47daca947b2d..ca043342c0eb 100644 --- a/include/net/netns/netfilter.h +++ b/include/net/netns/netfilter.h @@ -22,7 +22,9 @@ struct netns_nf { #ifdef CONFIG_NETFILTER_FAMILY_ARP struct nf_hook_entries __rcu *hooks_arp[NF_ARP_NUMHOOKS]; #endif +#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE struct nf_hook_entries __rcu *hooks_bridge[NF_INET_NUMHOOKS]; +#endif #if IS_ENABLED(CONFIG_DECNET) struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS]; #endif diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h index a0d89fd924c0..9bc5a12fdbb0 100644 --- a/include/net/netns/x_tables.h +++ b/include/net/netns/x_tables.h @@ -11,8 +11,11 @@ struct netns_xt { struct list_head tables[NFPROTO_NUMPROTO]; bool notrack_deprecated_warning; bool clusterip_deprecated_warning; +#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \ + defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE) struct ebt_table *broute_table; struct ebt_table *frame_filter; struct ebt_table *frame_nat; +#endif }; #endif diff --git a/include/net/sock.h b/include/net/sock.h index 94ffacc3683a..4e048167817d 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,6 +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; diff --git a/include/oneplus/control_center/control_center_helper.h b/include/oneplus/control_center/control_center_helper.h new file mode 100755 index 000000000000..106cadf274a7 --- /dev/null +++ b/include/oneplus/control_center/control_center_helper.h @@ -0,0 +1,222 @@ +/* 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); +#else +static inline void cc_tsk_init(void *task) {}; +static inline void cc_tsk_disable(void *task) {}; +static inline void cc_tsk_free(void *task) {}; + +extern u64 cc_cpu_find_ddr(int cpu) { return 0; } +extern bool cc_is_ddrfreq_related(const char *name) { return false; } +extern unsigned long cc_get_expect_ddrfreq(void) { return 0; } +extern 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 100755 index 000000000000..68129e3a4ec5 --- /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 100755 index 000000000000..d5c1beb7824a --- /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/memplus/memplus_helper.h b/include/oneplus/memplus/memplus_helper.h new file mode 100755 index 000000000000..82672a9e8c60 --- /dev/null +++ b/include/oneplus/memplus/memplus_helper.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _MEMORY_PLUS_HELPER_H +#define _MEMORY_PLUS_HELPER_H + +#ifdef CONFIG_MEMPLUS +#include + +struct memplus_cb_set { + bool (*memplus_enabled_cb)(void); + bool (*__memplus_enabled_cb)(void); + bool (*current_is_swapind_cb)(void); + void (*memplus_move_swapcache_to_anon_lru_cb)(struct page *page); + void (*memplus_move_anon_to_swapcache_lru_cb)(struct page *page); + void (*memplus_state_check_cb)(bool legacy, int oom_adj, + struct task_struct *task, int type, int update); + bool (*memplus_check_isolate_page_cb)(struct page *page); + void (*memplus_next_event_cb)(struct page *page); +}; +void register_cb_set(struct memplus_cb_set *set); +extern bool memplus_enabled(void); +extern bool __memplus_enabled(void); +extern bool current_is_swapind(void); +extern void memplus_move_swapcache_to_anon_lru(struct page *page); +extern void memplus_move_anon_to_swapcache_lru(struct page *page); +extern void memplus_state_check(bool legacy, int oom_adj, + struct task_struct *task, int type, int update); +extern bool memplus_check_isolate_page(struct page *page); +extern void memplus_next_event(struct page *page); + +#define memplus_init_task_reclaim_stat(sig) \ +do { \ + sig->swapin_should_readahead_m = 0; \ + sig->reclaim_state_lock = __SPIN_LOCK_UNLOCKED(reclaim_state_lock); \ + sig->memplus_type = 0; \ +} while (0) +#define __memplus_clear_entry(entry) ((entry).val = 0) +#define __memplus_entry(bdev_flag) ((bdev_flag) & SWP_SYNCHRONOUS_IO) +#define __get_memplus_swp_flag(entry) ((entry).val & SWP_SYNCHRONOUS_IO) +#define __set_memplus_entry(entry, flag) (entry.val = flag) +#define memplus_set_private(page, type) \ + set_page_private((page), __memplus_entry((type)?SWP_SYNCHRONOUS_IO:0)) + +#define memplus_set_willneed(page) \ +do { \ + if (current_is_swapind()) \ + SetPageWillneed(page); \ +} while (0) + +#define MEMPLUS_PAGE_LRU \ + (__memplus_enabled()?LRU_INACTIVE_ANON_SWPCACHE:LRU_INACTIVE_ANON) + +#define INIT_RECLAIM_STATE .reclaim_timeout = 0, \ + .swapin_should_readahead_m = 0, \ + .reclaim_state_lock = \ + __SPIN_LOCK_UNLOCKED(reclaim_state_lock), \ + .memplus_type = 0, + +#define memplus_page_to_lru(lru, page) (lru = page_lru(page)) +#else +static __always_inline +void memplus_move_swapcache_to_anon_lru(struct page *page) +{ + clear_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} +static __always_inline +void memplus_move_anon_to_swapcache_lru(struct page *page) +{ + set_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} +#define memplus_init_task_reclaim_stat(sig) +#define __memplus_clear_entry(entry) +#define __memplus_entry(bdev_flag) +#define __get_memplus_swp_flag(entry) +#define __set_memplus_entry(entry, flag) +#define memplus_set_private(page, type) +#define memplus_state_check(legacy, oom_adj, task, type, update) +static __always_inline bool memplus_enabled(void) +{ + return false; +} +static __always_inline bool __memplus_enabled(void) +{ + return false; +} +static __always_inline bool memplus_check_isolate_page(struct page *page) +{ + return false; +} + +#define MEMPLUS_PAGE_LRU LRU_INACTIVE_ANON + +#define INIT_RECLAIM_STATE + +#define memplus_page_to_lru(lru, page) + +#endif +#endif /* _MEMORY_PLUS_H */ diff --git a/include/oneplus/op_freezer/op_freezer.h b/include/oneplus/op_freezer/op_freezer.h new file mode 100755 index 000000000000..543187e5647f --- /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 (12) // 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 100755 index 000000000000..589f12a824dc --- /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 100755 index 000000000000..212214c01c48 --- /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 100755 index 000000000000..ea73b5639cea --- /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 c36860111932..df9a9fdcd6c8 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -72,6 +72,7 @@ #define WRITE_SAME 0x41 #define UNMAP 0x42 #define READ_TOC 0x43 +#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 100755 index 000000000000..b50330a2b78a --- /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 100755 index 000000000000..361461c69f17 --- /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/msm-poweroff.h b/include/soc/qcom/msm-poweroff.h new file mode 100644 index 000000000000..ad6ab4a3250f --- /dev/null +++ b/include/soc/qcom/msm-poweroff.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _MSM_POWEROFF_H +#define _MSM_POWEROFF_H + +extern void oem_force_minidump_mode(void); +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); +extern bool oem_get_twice_modemdump_state(void); + +#endif diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 989112764cb3..3085e52d4cd7 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); @@ -168,6 +169,7 @@ void complete_err_ready(struct subsys_device *subsys); void complete_shutdown_ack(struct subsys_device *subsys); struct subsys_device *find_subsys_device(const char *str); extern int wait_for_shutdown_ack(struct subsys_desc *desc); +extern void subsys_send_uevent_notify(struct subsys_desc *desc); #else static inline int subsys_get_restart_level(struct subsys_device *dev) @@ -180,6 +182,8 @@ 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; @@ -230,6 +234,7 @@ static inline int wait_for_shutdown_ack(struct subsys_desc *desc) { return -EOPNOTSUPP; } +static inline void subsys_send_uevent_notify(struct subsys_desc *desc) { } #endif /* CONFIG_MSM_SUBSYSTEM_RESTART */ #endif diff --git a/include/trace/events/block.h b/include/trace/events/block.h index 81b43f5bdf23..fe2bd0157282 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 a1675d43777e..560554b80ca3 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_MEMPLUS +#define IF_HAVE_PG_WILLNEED(flag, string) ,{1UL << flag, string} +#else +#define IF_HAVE_PG_WILLNEED(flag, string) +#endif + #define __def_pageflag_names \ {1UL << PG_locked, "locked" }, \ {1UL << PG_waiters, "waiters" }, \ @@ -105,7 +111,8 @@ 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" ) \ +IF_HAVE_PG_WILLNEED(PG_willneed, "willneed") #define show_page_flags(flags) \ (flags) ? __print_flags(flags, "|", \ diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 53a3fcd4ea08..6ea4c0e797d2 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -172,6 +172,78 @@ TRACE_EVENT(cpu_frequency_limits, (unsigned long)__entry->max_freq, (unsigned long)__entry->cpu_id) ); +#ifdef CONFIG_PCCORE +// 2020-05-11, 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-05-11, 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) +); +#endif TRACE_EVENT(cpu_frequency_switch_start, @@ -604,6 +676,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 +725,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 ae6480afb01c..1ae33b6267ba 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1221,11 +1221,11 @@ TRACE_EVENT(sched_task_util, int best_energy_cpu, bool sync, int need_idle, int fastpath, bool placement_boost, u64 start_t, bool stune_boosted, bool is_rtg, bool rtg_skip_min, - int start_cpu), + 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, - start_cpu), + is_uxtop), TP_STRUCT__entry( __field(int, pid) @@ -1247,6 +1247,7 @@ TRACE_EVENT(sched_task_util, __field(u32, unfilter) __field(unsigned long, cpus_allowed) __field(bool, low_latency) + __field(bool, is_uxtop) ), TP_fast_assign( @@ -1264,7 +1265,6 @@ TRACE_EVENT(sched_task_util, __entry->stune_boosted = stune_boosted; __entry->is_rtg = is_rtg; __entry->rtg_skip_min = rtg_skip_min; - __entry->start_cpu = start_cpu; #ifdef CONFIG_SCHED_WALT __entry->unfilter = p->unfilter; __entry->low_latency = p->low_latency; @@ -1272,16 +1272,17 @@ TRACE_EVENT(sched_task_util, __entry->unfilter = 0; __entry->low_latency = 0; #endif - __entry->cpus_allowed = cpumask_bits(&p->cpus_allowed)[0]; + __entry->cpus_allowed = cpumask_bits(&p->cpus_allowed)[0]; + __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 start_cpu=%d unfilter=%u affine=%#lx low_latency=%d", + 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 start_cpu=%d unfilter=%u affine=%#lx low_latency=%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->start_cpu, - __entry->unfilter, __entry->cpus_allowed, __entry->low_latency) + __entry->unfilter, __entry->cpus_allowed, __entry->low_latency, __entry->is_uxtop) ); /* diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 214bc1bc81fa..31480d3e55ff 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -27,6 +27,9 @@ #include "drm.h" #include "sde_drm.h" +#if defined(CONFIG_PXLW_IRIS) || defined(PXLW_IRIS5) || defined(CONFIG_PXLW_SOFT_IRIS) || defined(PXLW_SOFT_IRIS_ONLY) +#include "msm_drm_iris.h" +#endif // CONFIG_PXLW_IRIS || PXLW_IRIS5 #if defined(__cplusplus) extern "C" { diff --git a/include/uapi/drm/msm_drm_iris.h b/include/uapi/drm/msm_drm_iris.h new file mode 100644 index 000000000000..16000ba4a85c --- /dev/null +++ b/include/uapi/drm/msm_drm_iris.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +#ifndef __MSM_DRM_IRIS_H__ +#define __MSM_DRM_IRIS_H__ + +#define DRM_MSM_IRIS_OPERATE_CONF 0x50 +#define DRM_MSM_IRIS_OPERATE_TOOL 0x51 + +enum iris_oprt_type { + IRIS_OPRT_TOOL_DSI, + IRIS_OPRT_CONFIGURE, + IRIS_OPRT_CONFIGURE_NEW, + IRIS_OPRT_CONFIGURE_NEW_GET, + IRIS_OPRT_MAX_TYPE, +}; + +struct msmfb_mipi_dsi_cmd { + __u8 dtype; + __u8 vc; +#define MSMFB_MIPI_DSI_COMMAND_LAST 1 +#define MSMFB_MIPI_DSI_COMMAND_ACK 2 +#define MSMFB_MIPI_DSI_COMMAND_HS 4 +#define MSMFB_MIPI_DSI_COMMAND_BLLP 8 +#define MSMFB_MIPI_DSI_COMMAND_DEBUG 16 +#define MSMFB_MIPI_DSI_COMMAND_TO_PANEL 32 +#define MSMFB_MIPI_DSI_COMMAND_T 64 + + __u32 iris_ocp_type; + __u32 iris_ocp_addr; + __u32 iris_ocp_value; + __u32 iris_ocp_size; + + __u16 flags; + __u16 length; + __u8 *payload; + __u8 response[16]; +}; + +struct msm_iris_operate_value { + unsigned int type; + unsigned int count; + void *values; +}; + +struct msmfb_iris_ambient_info { + uint32_t ambient_lux; + uint32_t ambient_bl_ratio; + void *lut_lut2_payload; +}; +struct msmfb_iris_maxcll_info { + uint32_t mMAXCLL; + void *lut_luty_payload; + void *lut_lutuv_payload; + }; +#define DRM_IOCTL_MSM_IRIS_OPERATE_CONF \ + DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_CONF, struct msm_iris_operate_value) +#define DRM_IOCTL_MSM_IRIS_OPERATE_TOOL \ + DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_TOOL, struct msm_iris_operate_value) + +#endif /* __MSM_DRM_IRIS_H__ */ diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 24af4edfc98c..9abec63a0f16 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 5fa3fcc10128..db81a3c13435 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -30,7 +30,13 @@ #define NETLINK_CRYPTO 21 /* Crypto layer */ #define NETLINK_SMC 22 /* SMC monitoring */ #define NETLINK_SOCKEV 23 /* Socket Administrative Events */ +#ifdef CONFIG_OP_FREEZER +#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 a4c11c12fdf1..6979396f655b 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 22a0a7e81860..63e345b4ab26 100644 --- a/include/uapi/scsi/ufs/ufs.h +++ b/include/uapi/scsi/ufs/ufs.h @@ -20,6 +20,14 @@ enum flag_idn { QUERY_FLAG_IDN_WB_EN = 0x0E, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10, +#if defined(CONFIG_UFSHPB) && defined(UFS3V1) + QUERY_FLAG_IDN_HPB_RESET = 0x11, +#endif +#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 }; /* Attribute idn for Query requests */ @@ -52,6 +60,21 @@ enum attr_idn { QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F, +#if defined(CONFIG_UFSTW) + QUERY_ATTR_IDN_TW_FLUSH_STATUS = 0x1C, +#if defined(UFS3V1) + QUERY_ATTR_IDN_TW_AVAIL_BUF_SIZE = 0x1D, +#elif defined(UFS3V0) + QUERY_ATTR_IDN_TW_BUF_SIZE = 0x1D, +#endif + QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST = 0x1E, +#if defined(UFS3V1) + QUERY_ATTR_IDN_TW_CURR_BUF_SIZE = 0x1F, +#endif +#endif +#if defined(CONFIG_UFSFEATURE) + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS = 0xFF, +#endif }; #define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02 diff --git a/init/init_task.c b/init/init_task.c index 53e6e27ea8b5..b11843b67729 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -42,6 +42,7 @@ static struct signal_struct init_signals = { [PIDTYPE_SID] = &init_struct_pid, }, INIT_PREV_CPUTIME(init_signals) + INIT_RECLAIM_STATE }; static struct sighand_struct init_sighand = { diff --git a/init/main.c b/init/main.c index 7942ad3cdb42..c218b5a355ea 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 0a39b26d6e4d..06c406f3993b 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -540,6 +540,7 @@ static ssize_t __cgroup1_procs_write(struct kernfs_open_file *of, cred = current_cred(); tcred = get_task_cred(task); 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/freezer.c b/kernel/cgroup/freezer.c index 08236798d173..6310db1399ff 100644 --- a/kernel/cgroup/freezer.c +++ b/kernel/cgroup/freezer.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include /* * A cgroup is freezing if any FREEZING flags are set. FREEZING_SELF is @@ -43,6 +45,7 @@ enum freezer_state_flags { struct freezer { struct cgroup_subsys_state css; unsigned int state; + unsigned int oem_freeze_flag; }; static DEFINE_MUTEX(freezer_mutex); @@ -322,7 +325,7 @@ 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); + freeze_cgroup_task(task); css_task_iter_end(&it); } @@ -330,11 +333,24 @@ static void unfreeze_cgroup(struct freezer *freezer) { struct css_task_iter it; struct task_struct *task; + 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))) + 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); + + 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 +408,7 @@ static void freezer_change_state(struct freezer *freezer, bool freeze) * CGROUP_FREEZING_PARENT. */ mutex_lock(&freezer_mutex); + 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 +433,27 @@ static void freezer_change_state(struct freezer *freezer, bool freeze) mutex_unlock(&freezer_mutex); } +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 fb93388c9f0c..4694524fc4b8 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,34 @@ 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 +10877,82 @@ 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 +11037,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 +11068,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 +11400,11 @@ 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 +11435,10 @@ err_group_fd: 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 c73ebbaf519a..b7c73bc49784 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -68,6 +68,12 @@ #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif +#ifdef CONFIG_HOUSTON +#include +#endif static void __unhash_process(struct task_struct *p, bool group_dead) { nr_threads--; @@ -176,6 +182,10 @@ 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 + perf_event_delayed_put(tsk); trace_sched_process_free(tsk); put_task_struct(tsk); @@ -186,6 +196,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 */ @@ -881,6 +900,13 @@ void __noreturn do_exit(long code) exit_task_namespaces(tsk); 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 diff --git a/kernel/fork.c b/kernel/fork.c index 68b80fcf94bd..f455916f7a92 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -95,6 +95,12 @@ #include #include #include +#ifdef CONFIG_HOUSTON +#include +#endif +#ifdef CONFIG_CONTROL_CENTER +#include +#endif #include #include @@ -138,6 +144,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 +917,27 @@ 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_CONTROL_CENTER + tsk->nice_effect_ts = 0; + tsk->cached_prio = tsk->static_prio; +#endif +/* 2020-05-19 add for uxrealm*/ +#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 account_kernel_stack(tsk, 1); @@ -924,6 +955,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #ifdef CONFIG_MEMCG tsk->active_memcg = NULL; #endif + +#ifdef CONFIG_TPD + tsk->tpd = 0; +#endif return tsk; free_stack: @@ -986,6 +1021,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 @@ -1575,6 +1612,10 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->oom_score_adj = current->signal->oom_score_adj; sig->oom_score_adj_min = current->signal->oom_score_adj_min; + /* CONFIG_MEMPLUS add start by bin.zhong@ASTI */ + memplus_init_task_reclaim_stat(sig); + /* add end */ + mutex_init(&sig->cred_guard_mutex); return 0; @@ -1968,6 +2009,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 +2066,11 @@ static __latent_entropy struct task_struct *copy_process( p->sequential_io = 0; p->sequential_io_avg = 0; #endif - +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 +2308,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: diff --git a/kernel/freezer.c b/kernel/freezer.c index b162b74611e4..4bfeca13dd3a 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -73,7 +73,8 @@ bool __refrigerator(bool check_kthr_stop) spin_lock_irq(&freezer_lock); current->flags |= PF_FROZEN; if (!freezing(current) || - (check_kthr_stop && kthread_should_stop())) + (check_kthr_stop && kthread_should_stop()) || + current->kill_flag) current->flags &= ~PF_FROZEN; spin_unlock_irq(&freezer_lock); @@ -106,6 +107,25 @@ static void fake_signal_wake_up(struct task_struct *p) } } +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 920d853a8e9e..e38d60610f3a 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! @@ -1613,6 +1616,15 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) if (!hb_waiters_pending(hb)) goto out_put_key; +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && current->dynamic_ux) { + if (current->saved_flag) { + set_user_nice(current, PRIO_TO_NICE(current->prio_saved)); + current->saved_flag = 0; + } + uxchain_dynamic_ux_reset(current); + } +#endif spin_lock(&hb->lock); plist_for_each_entry_safe(this, next, &hb->chain, list) { @@ -2597,8 +2609,14 @@ out: * @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 +2641,39 @@ 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) { + wait_for->saved_flag = 1; + wait_for->prio_saved = wait_for->normal_prio; + set_user_nice(wait_for, PRIO_TO_NICE(current->normal_prio)); + } + if (wait_for) { + put_task_struct(wait_for); + wait_for = NULL; + } + } + freezable_schedule(); + } +#elif defined(CONFIG_ONEPLUS_HEALTHINFO) + 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 +2753,33 @@ out: 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 +2797,28 @@ retry: * 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); +#else futex_wait_queue_me(hb, &q, to); +#endif +#ifdef CONFIG_UXCHAIN + wait_for = NULL; +#endif /* If we were woken (and unqueued), we succeeded, whatever. */ ret = 0; @@ -2768,6 +2847,9 @@ retry: 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 +2873,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 +3371,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 +3797,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 11f10e0169d0..1a586f8ebb02 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 eb69b805f908..4ca8513db75c 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 49dc6f3620f0..731a4153a3c1 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 202ef0d29fb6..a045524eac24 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -1011,7 +1011,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, } spin_unlock(&lock->wait_lock); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (state & TASK_UNINTERRUPTIBLE) + current->in_mutex = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule_preempt_disabled(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 ddc9cbd7700b..c34f2a0753c0 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -285,7 +285,13 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state) raw_spin_unlock_irq(&sem->wait_lock); break; } +#ifdef CONFIG_ONEPLUS_HEALTHINFO + current->in_downread = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + current->in_downread = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ } __set_current_state(TASK_RUNNING); @@ -587,7 +593,13 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) if (signal_pending_state(state, current)) goto out_nolock; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + current->in_downwrite = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + 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 50033a73d6c6..c1c13ab872dd 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; /* * Disable local interrupts. This will prevent panic_smp_self_stop @@ -179,7 +181,17 @@ 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); + 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 6bcb47d366af..7c5d065aa0d6 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 32a55ecb78d6..533454f5075f 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -114,6 +114,134 @@ static struct pm_qos_object network_throughput_pm_qos = { .name = "network_throughput", }; +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(memory_bandwidth_notifier); static struct pm_qos_constraints memory_bw_constraints = { @@ -129,6 +257,89 @@ static struct pm_qos_object memory_bandwidth_pm_qos = { .name = "memory_bandwidth", }; +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 +347,20 @@ static struct pm_qos_object *pm_qos_array[] = { &network_lat_pm_qos, &network_throughput_pm_qos, &memory_bandwidth_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, + &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, }; static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, @@ -648,11 +873,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/printk/printk.c b/kernel/printk/printk.c index a9e567ac6ce4..fce3f6f63f69 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 4fef5894b9d2..1b1da05f77e7 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 81f880bc9565..fe5fe80abf67 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -24,11 +24,22 @@ #include "pelt.h" #include "walt.h" - +#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 +#ifdef TRACE_DEBUG +#define SYSTRACE_MAGIC 99990 +#endif #if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_JUMP_LABEL) /* @@ -1376,6 +1387,10 @@ 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 +1476,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 +2117,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 @@ -2189,11 +2219,14 @@ 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) +// 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 +2243,13 @@ 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)) +// 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,7 +3075,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 +3085,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); @@ -4282,9 +4327,21 @@ static void __sched notrace __schedule(bool preempt) * is a RELEASE barrier), */ ++*switch_count; +#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,7 +4738,34 @@ static inline int rt_effective_prio(struct task_struct *p, int prio) } #endif -void set_user_nice(struct task_struct *p, long nice) +#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; @@ -4734,6 +4818,76 @@ void set_user_nice(struct task_struct *p, long nice) 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; + int old_prio, delta; + 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. + */ + 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); +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = p->static_prio; +#endif + 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); +#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); + 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); /* @@ -4880,7 +5034,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 @@ -6732,6 +6891,15 @@ int sched_isolate_count(const cpumask_t *mask, bool include_offline) return cpumask_weight(&count_mask); } +static inline void tracing_mark_write(int serial, char *name, unsigned int value) +{ +#ifdef TRACE_DEBUG + trace_printk("C|%d|%s|%u\n", SYSTRACE_MAGIC+serial, name, value); +#else + pr_info("trace func:%s cpu:%d value:%d\n", name, serial, value); +#endif +} + /* * 1) CPU is isolated and cpu is offlined: * Unisolate the core. @@ -6798,7 +6966,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 +7015,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 dc695b0db063..19632d747d41 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,20 @@ 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 +#ifdef TRACE_DEBUG +#define SYSTRACE_MAGIC 99990 +#endif + +static inline void tracing_mark_write(int serial, char *name, unsigned int value) +{ +#ifdef TRACE_DEBUG + trace_printk("C|%d|%s|%u\n", SYSTRACE_MAGIC+serial, name, value); +#else + pr_info("trace func:%s value:%d\n", name, value); +#endif +} + static bool need_all_cpus(const struct cluster_data *cluster) { @@ -787,7 +806,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 +1266,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 af3f3c04c66e..34af80f538ab 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -17,6 +17,12 @@ #include #include +#ifdef CONFIG_HOUSTON +#include +#endif +#ifdef CONFIG_CONTROL_CENTER +#include +#endif struct sugov_tunables { struct gov_attr_set attr_set; unsigned int up_rate_limit_us; @@ -235,6 +241,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 +291,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 +300,8 @@ 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 +344,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 +372,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 } /* @@ -652,6 +718,9 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, unsigned long util, max, hs_util, boost_util; 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 +774,9 @@ 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 @@ -775,6 +847,9 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) struct sugov_policy *sg_policy = sg_cpu->sg_policy; 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 +885,9 @@ 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 +1424,16 @@ 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 +1442,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/fair.c b/kernel/sched/fair.c index aafa7af42609..318352087c48 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -25,6 +25,31 @@ #include #include "walt.h" +#ifdef CONFIG_OPCHAIN +//2020-05-19, add for uxrealm CONFIG_OPCHAIN +#include +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#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); @@ -87,6 +112,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 * @@ -602,6 +635,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: */ @@ -882,6 +945,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; @@ -903,9 +971,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); @@ -933,6 +1030,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) @@ -956,6 +1058,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); } @@ -964,6 +1074,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 @@ -996,6 +1107,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) { @@ -1015,8 +1130,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); @@ -3927,6 +4055,18 @@ bias_to_this_cpu(struct task_struct *p, int cpu, int start_cpu) 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; + + 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; } @@ -3992,6 +4132,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, @@ -4209,6 +4352,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 +4374,28 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) if (renorm && !curr) se->vruntime += cfs_rq->min_vruntime; +#if defined(CONFIG_UXCHAIN) && defined(CONFIG_OPCHAIN) + 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 +4409,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 +4505,20 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) se->on_rq = 0; account_entity_dequeue(cfs_rq, se); +#if defined(CONFIG_UXCHAIN) && defined(CONFIG_OPCHAIN) + 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 +4553,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) { @@ -5472,7 +5671,10 @@ 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 + // 2020-05-20 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. @@ -5595,7 +5797,10 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; int task_sleep = flags & DEQUEUE_SLEEP; - +#ifdef CONFIG_OPCHAIN + //2020-05-19 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. @@ -6871,12 +7076,40 @@ static int get_start_cpu(struct task_struct *p) task_boost_policy(p) == SCHED_BOOST_ON_BIG || task_boost == TASK_BOOST_ON_MID; bool task_skip_min = task_skip_min_cpu(p); +#ifdef CONFIG_OPCHAIN + // 2020-05-19, add for uxrealm CONFIG_OPCHAIN + bool is_uxtop = is_opc_task(p, UT_FORE); +#endif +#if defined(CONFIG_HOUSTON) && defined(CONFIG_OPCHAIN) + if (is_uxtop && current->ravg.demand_scaled >= p->ravg.demand_scaled) { + /* add 'current' into RTG list */ + ht_rtg_list_add_tail(current); + } +#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 defined(CONFIG_CONTROL_CENTER) && defined(CONFIG_IM) + if ((im_rendering(p)) && + im_render_grouping_enable() && + ccdm_get_hint(CCDM_TB_PLACE_BOOST) && + task_util(p) > ccdm_get_min_util_threshold()) { + start_cpu = rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + return start_cpu; + } +#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 + if (task_skip_min || boosted) { start_cpu = rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; @@ -6900,6 +7133,13 @@ static int get_start_cpu(struct task_struct *p) !task_demand_fits(p, start_cpu)) start_cpu = rd->max_cap_orig_cpu; +#ifdef CONFIG_TPD + if (is_tpd_enable() && is_tpd_task(p)) { + 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 +7149,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) @@ -6938,6 +7179,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, int isolated_candidate = -1; unsigned int target_nr_rtg_high_prio = UINT_MAX; bool rtg_high_prio_task = task_rtg_high_prio(p); + bool is_rtg; + cpumask_t new_allowed_cpus; +#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 @@ -6979,8 +7225,22 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, /* 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); + else { + cpumask_copy(&new_allowed_cpus, &p->cpus_allowed); +#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 +7252,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 +7289,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 + // 2020-05-19, 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 +7639,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) { @@ -7723,6 +8022,12 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int delta = 0; int task_boost = per_task_boost(p); int boosted = (schedtune_task_boost(p) > 0) || (task_boost > 0); + +#ifdef CONFIG_OPCHAIN + // 200-05-19, add for uxrealm CONFIG_OPCHAIN + bool is_uxtop = is_opc_task(p, UT_FORE); +#endif + int start_cpu; if (is_many_wakeup(sibling_count_hint) && prev_cpu != cpu && @@ -7739,6 +8044,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 && !im_launcher(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 +8061,15 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, if (sync && (need_idle || (is_rtg && curr_is_rtg))) sync = 0; - + //2020-05-19, add for uxrealm CONFIG_OPCHAIN +#ifdef CONFIG_OPCHAIN if (sysctl_sched_sync_hint_enable && sync && - bias_to_this_cpu(p, cpu, start_cpu)) { + 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 +8145,16 @@ 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_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)) { +#endif best_energy_cpu = cpu; goto unlock; } @@ -7874,8 +8200,7 @@ done: 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); - + get_rtg_status(p), is_uxtop); return best_energy_cpu; fail: @@ -8557,7 +8882,11 @@ enum group_type { #define LBF_NOHZ_AGAIN 0x20 #define LBF_IGNORE_BIG_TASKS 0x100 #define LBF_IGNORE_PREFERRED_CLUSTER_TASKS 0x200 - +// 2020-05-19, add for uxrealm CONFIG_OPCHAIN +#ifdef CONFIG_OPCHAIN +#define LBF_IGNORE_UX_TOP 0x800 +#define LBF_IGNORE_SLAVE 0xC00 +#endif struct lb_env { struct sched_domain *sd; @@ -8683,6 +9012,17 @@ 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) { +#ifdef CONFIG_TPD + struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + int mid_core; + + 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))) @@ -8777,7 +9117,13 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) !task_fits_max(p, env->dst_cpu)) return 0; #endif - +#ifdef CONFIG_OPCHAIN + //2020-05-19, 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; @@ -8876,7 +9222,10 @@ static int detach_tasks(struct lb_env *env) int detached = 0; int orig_loop = env->loop; u64 start_t = rq_clock(env->src_rq); - +#ifdef CONFIG_OPCHAIN + //2020-05-19, add for uxrealm CONFIG_OPCHAIN + int src_claim = opc_get_claim_on_cpu(env->src_cpu); +#endif lockdep_assert_held(&env->src_rq->lock); if (env->imbalance <= 0) @@ -8886,9 +9235,13 @@ static int detach_tasks(struct lb_env *env) if (!same_cluster(env->dst_cpu, env->src_cpu)) env->flags |= LBF_IGNORE_PREFERRED_CLUSTER_TASKS; - if (capacity_orig_of(env->dst_cpu) < - capacity_orig_of(env->src_cpu)) + 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; + } } redo: @@ -8982,6 +9335,11 @@ next: tasks = &env->src_rq->cfs_tasks; env->flags &= ~(LBF_IGNORE_BIG_TASKS | LBF_IGNORE_PREFERRED_CLUSTER_TASKS); +#ifdef CONFIG_OPCHAIN + //2020-05-19, 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 0b2bc6c5a291..e00933bb4d34 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -10,6 +10,18 @@ #include #include "walt.h" +#ifdef CONFIG_CONTROL_CENTER +#include +#endif +#ifdef CONFIG_IM +#include +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif/**/ +#ifdef CONFIG_OPCHAIN +#include +#endif int sched_rr_timeslice = RR_TIMESLICE; int sysctl_sched_rr_timeslice = (MSEC_PER_SEC / HZ) * RR_TIMESLICE; @@ -1033,6 +1045,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; @@ -1046,6 +1063,37 @@ static void update_curr_rt(struct rq *rq) curr->se.sum_exec_runtime += delta_exec; account_group_exec_runtime(curr, delta_exec); +#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); @@ -1062,6 +1110,10 @@ 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); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ohm_rtinfo_ctrl == true) + rt_info_record(rt_rq, cpu_of(rq_of_rt_rq(rt_rq))); +#endif } } } @@ -1423,6 +1475,9 @@ 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 + p->rtend_time = rq_clock_task(rq); +#endif dequeue_rt_entity(rt_se, flags); walt_dec_cumulative_runnable_avg(rq, p); @@ -1645,7 +1700,9 @@ 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 + p->rtstart_time = rq_clock_task(rq); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ return p; } @@ -1769,6 +1826,12 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) int best_cpu_idle_idx = INT_MAX; int cpu_idle_idx = -1; bool boost_on_big = rt_boost_on_big(); +#ifdef 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(); @@ -1780,6 +1843,12 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) 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 { @@ -1795,6 +1864,15 @@ retry: } 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 + if (cpu_isolated(cpu)) continue; @@ -1805,7 +1883,16 @@ retry: if (__cpu_overutilized(cpu, util + tutil)) continue; - +#ifdef 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) continue; @@ -1837,6 +1924,14 @@ retry: continue; } +#ifdef 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 3aaf465ac759..a8278d65740d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -83,6 +83,9 @@ #endif #include "tune.h" +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ struct rq; struct cpuidle_state; @@ -90,6 +93,13 @@ struct cpuidle_state; extern __read_mostly bool sched_predl; extern unsigned int sched_capacity_margin_up[NR_CPUS]; extern unsigned int sched_capacity_margin_down[NR_CPUS]; +#ifdef CONFIG_IM +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; @@ -98,6 +108,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 +154,9 @@ struct sched_cluster { unsigned int max_possible_freq; bool freq_init_done; u64 aggr_grp_load; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + struct sched_stat_para *overload; +#endif }; extern cpumask_t asym_cap_sibling_cpus; @@ -1113,7 +1127,12 @@ struct rq { #ifdef CONFIG_SMP struct llist_head wake_list; #endif - +#ifdef CONFIG_ONEPLUS_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 +2065,10 @@ 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 + 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 +2081,19 @@ 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 + 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 + 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/walt.c b/kernel/sched/walt.c index 11aae77c134e..5f4ba320d8ea 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,13 @@ 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 + 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) @@ -2660,6 +2670,7 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp, * The children inherits the group id from the parent. */ unsigned int __read_mostly sysctl_sched_coloc_downmigrate_ns; +unsigned int __read_mostly sysctl_sched_enable_thread_grouping; struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID]; static LIST_HEAD(active_related_thread_groups); @@ -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())) @@ -2930,6 +2941,20 @@ void add_new_task_to_grp(struct task_struct *new) { unsigned long flags; struct related_thread_group *grp; + struct task_struct *leader = new->group_leader; + unsigned int leader_grp_id = sched_get_group_id(leader); + +#ifdef CONFIG_IM + if (im_sf(new)) { + // add child of sf into rdg + if (!im_render_grouping_enable()) + im_list_add_task(new); + } +#endif + + if (!sysctl_sched_enable_thread_grouping && + leader_grp_id != DEFAULT_CGROUP_COLOC_ID) + return; /* * If the task does not belong to colocated schedtune @@ -3679,6 +3704,62 @@ unlock: return ret; } +#ifdef CONFIG_IM +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 96667620acad..a42541284e7d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1083,6 +1083,18 @@ 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 +1106,20 @@ 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 +1293,19 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, unsigned long flags; int ret = -ESRCH; + 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 +3356,17 @@ 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); + 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 a90672c6e9b6..8655779a2073 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,12 @@ 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 +346,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 +363,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 +451,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, @@ -1130,7 +1165,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", @@ -1436,7 +1471,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 { @@ -1578,6 +1631,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 + { } }; @@ -1707,8 +1777,24 @@ 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, @@ -2870,6 +2956,25 @@ 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); + else + return -EPERM; +} +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 81ee5b83c920..e03f354b1a96 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 21bb161c2316..2daf57b6f82d 100644 --- a/kernel/trace/power-traces.c +++ b/kernel/trace/power-traces.c @@ -18,4 +18,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_frequency); EXPORT_TRACEPOINT_SYMBOL_GPL(powernv_throttle); +#ifdef CONFIG_PCCORE +EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_frequency_select); +#endif diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index c606f6a07bd0..31e2524cc64d 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -17,6 +17,10 @@ #include #include #include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#include <../sched/sched.h> +#endif #include "trace.h" @@ -622,7 +626,11 @@ struct irqsoff_store { static DEFINE_PER_CPU(struct irqsoff_store, the_irqsoff); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +unsigned int ohm_irqsoff_stat_thresh = 1000000UL; +DEFINE_PER_CPU(u64, irqsoff_stime); +#endif /* * We are only interested in hardirq on/off events: */ @@ -645,7 +653,15 @@ void tracer_hardirqs_on(unsigned long a0, unsigned long a1) is->ts = 0; lockdep_on(); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ +#ifdef CONFIG_ONEPLUS_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*/ if (!preempt_trace(pc) && irq_trace()) stop_critical_timing(a0, a1, pc); } @@ -666,7 +682,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 +743,10 @@ struct preempt_store { static DEFINE_PER_CPU(struct preempt_store, the_ps); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ +#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 +784,15 @@ 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 + 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 +817,12 @@ 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 + 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 e6b68cf40aae..49147d3cd4c8 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -52,6 +52,9 @@ #include #include +#ifdef CONFIG_IM +#include +#endif #include "workqueue_internal.h" enum { @@ -1857,6 +1860,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 236eb21167b5..6958b8dc4572 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 @@ next: 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 @@ next: 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 @@ next: 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 0beaa1d899aa..300e9380737c 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 210a06eb94c4..35a3abbec426 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -860,3 +860,13 @@ 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 154213214ab3..bdfe6af123c6 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 @@ -2192,6 +2196,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; @@ -2673,6 +2683,9 @@ vm_fault_t filemap_fault(struct vm_fault *vmf) */ fpin = do_async_mmap_readahead(vmf, page); } else if (!page) { +#ifdef CONFIG_MEMPLUS + count_vm_event(FILEMAJFAULT); +#endif /* No page in the page cache at all */ count_vm_event(PGMAJFAULT); count_memcg_event_mm(vmf->vma->vm_mm, PGMAJFAULT); @@ -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/memcontrol.c b/mm/memcontrol.c index 3b78b6af353b..336ccf4247ee 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -105,6 +105,10 @@ static const char *const mem_cgroup_lru_names[] = { "active_anon", "inactive_file", "active_file", +#ifdef CONFIG_MEMPLUS + "inactive_anon_swpcache", + "active_anon_swpcache", +#endif "unevictable", }; diff --git a/mm/memory.c b/mm/memory.c index cb7f36f7bc94..faf759bc79fa 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2924,7 +2924,9 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf) __releases(vmf->ptl) { struct vm_area_struct *vma = vmf->vma; - +#ifdef CONFIG_MEMPLUS + count_vm_event(WPFAULT); +#endif vmf->page = __vm_normal_page(vma, vmf->address, vmf->orig_pte, false, vmf->vma_flags); if (!vmf->page) { @@ -3214,6 +3216,9 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) /* Had to read the page from swap area: Major fault */ ret = VM_FAULT_MAJOR; count_vm_event(PGMAJFAULT); +#ifdef CONFIG_MEMPLUS + count_vm_event(SWAPMAJFAULT); +#endif count_memcg_event_mm(vma->vm_mm, PGMAJFAULT); } else if (PageHWPoison(page)) { /* @@ -3368,6 +3373,10 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf) vm_fault_t ret = 0; pte_t entry; +#ifdef CONFIG_MEMPLUS + count_vm_event(ANONFAULT); +#endif + /* File mapping without ->vm_ops ? */ if (vmf->vma_flags & VM_SHARED) return VM_FAULT_SIGBUS; @@ -4069,12 +4078,22 @@ static vm_fault_t do_fault(struct vm_fault *vmf) pte_unmap_unlock(vmf->pte, vmf->ptl); } - } else if (!(vmf->flags & FAULT_FLAG_WRITE)) + } else if (!(vmf->flags & FAULT_FLAG_WRITE)) { ret = do_read_fault(vmf); - else if (!(vmf->vma_flags & VM_SHARED)) +#ifdef CONFIG_MEMPLUS + count_vm_event(READFAULT); +#endif + } else if (!(vmf->vma_flags & VM_SHARED)) { ret = do_cow_fault(vmf); - else +#ifdef CONFIG_MEMPLUS + count_vm_event(COWFAULT); +#endif + } else { ret = do_shared_fault(vmf); +#ifdef CONFIG_MEMPLUS + count_vm_event(SHAREDFAULT); +#endif + } /* preallocated pagetable is unused: free it */ if (vmf->prealloc_pte) { @@ -4317,8 +4336,12 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) return do_fault(vmf); } - if (!pte_present(vmf->orig_pte)) + if (!pte_present(vmf->orig_pte)) { +#ifdef CONFIG_MEMPLUS + count_vm_event(SWAPFAULT); +#endif return do_swap_page(vmf); + } if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) return do_numa_page(vmf); @@ -4649,6 +4672,10 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address, put_vma(vmf.vma); *vma = NULL; } +#ifdef CONFIG_MEMPLUS + else + count_vm_event(SPECRETRY); +#endif /* * The task may have entered a memcg OOM situation but diff --git a/mm/mmap.c b/mm/mmap.c index 85f87e882d4c..657cdadbd857 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 @@ out: 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,14 @@ 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 23c57dbd625e..9ea6641256db 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 078f1461e074..a58953a8058f 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 c9665e0a6865..8fb7c09de402 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -73,6 +73,10 @@ #include #include #include "internal.h" +#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 +300,9 @@ char * const migratetype_names[MIGRATE_TYPES] = { "CMA", #endif "HighAtomic", +#ifdef CONFIG_DEFRAG + "Defrag-Pool", +#endif #ifdef CONFIG_MEMORY_ISOLATION "Isolate", #endif @@ -2146,6 +2153,9 @@ 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 +2504,9 @@ static void reserve_highatomic_pageblock(struct page *page, struct zone *zone, /* Yoink! */ mt = get_pageblock_migratetype(page); + 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 +2729,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 +3321,10 @@ 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)); + page = defrag_alloc(zone, flags, migratetype, order); + if (page) + goto out; + spin_lock_irqsave(&zone->lock, flags); do { @@ -3467,6 +3493,7 @@ 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 + free_pages -= defrag_calc(z, order, alloc_flags); /* * Check watermarks for an order-0 allocation request. If these @@ -3507,6 +3534,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; } #endif + 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 +3563,7 @@ 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 + cma_pages += defrag_zone_free_size(z); /* * Fast check for order-0 only. If this fails then the reserves @@ -4329,6 +4361,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask) (gfp_mask & __GFP_CMA)) alloc_flags |= ALLOC_CMA; #endif + + defrag_migrate_to_alloc_flag(alloc_flags, + gfpflags_to_migratetype(gfp_mask)); + return alloc_flags; } @@ -4524,6 +4560,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 +4802,9 @@ fail: 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; } @@ -4796,6 +4838,8 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order, (gfp_mask & __GFP_CMA)) *alloc_flags |= ALLOC_CMA; + defrag_migrate_to_alloc_flag(*alloc_flags, ac->migratetype); + return true; } @@ -4842,6 +4886,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid, finalise_ac(gfp_mask, &ac); + ADD_ORDER_USAGE(order); /* * Forbid the first pass from falling back to types that fragment * memory until all local zones are considered. @@ -4852,6 +4897,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid, page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac); if (likely(page)) goto out; + ADD_ORDER_FAIL(order); /* * Apply scoped allocation constraints. This is mainly about GFP_NOFS @@ -5300,6 +5346,9 @@ static void show_migration_types(unsigned char type) #endif #ifdef CONFIG_MEMORY_ISOLATION [MIGRATE_ISOLATE] = 'I', +#endif +#ifdef CONFIG_DEFRAG + [MIGRATE_UNMOVABLE_DEFRAG_POOL] = 'D', #endif }; char tmp[MIGRATE_TYPES + 1]; diff --git a/mm/page_poison.c b/mm/page_poison.c index 9bec1f7c9250..858ac75959a9 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/readahead.c b/mm/readahead.c index 4e630143a0ba..f4788b2c0619 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -523,7 +523,9 @@ void page_cache_sync_readahead(struct address_space *mapping, force_page_cache_readahead(mapping, filp, offset, req_size); return; } - +#ifdef CONFIG_MEMPLUS + count_vm_event(PGCACHEMISS); +#endif /* do read-ahead */ ondemand_readahead(mapping, ra, filp, false, offset, req_size); } diff --git a/mm/shmem.c b/mm/shmem.c index 44ae07981ead..b124a2f5a40f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1343,6 +1343,8 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) SetPageUptodate(page); } + memplus_set_private(page, 1); + /* add end */ swap = get_swap_page(page); if (!swap.val) goto redirty; diff --git a/mm/swap_slots.c b/mm/swap_slots.c index c8828c3757ff..f17b2bbf0862 100644 --- a/mm/swap_slots.c +++ b/mm/swap_slots.c @@ -353,6 +353,8 @@ repeat: goto out; } + __set_memplus_entry(entry, page_private(page)); + /* add end */ get_swap_pages(1, &entry, 1); out: if (mem_cgroup_try_charge_swap(page, entry)) { diff --git a/mm/swap_state.c b/mm/swap_state.c index 356322c0fcfe..8e6ec34ca250 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -449,7 +449,10 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * Initiate read into locked page and return. */ SetPageWorkingset(new_page); - lru_cache_add_anon(new_page); + if (memplus_enabled()) + __lru_cache_add_active_or_unevictable(new_page, 0); + else /* add end */ + lru_cache_add_anon(new_page); *new_page_allocated = true; return new_page; } diff --git a/mm/swapfile.c b/mm/swapfile.c index b644151b7f34..a5addf7a204f 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -957,6 +957,11 @@ int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_size) int n_ret = 0; int node; int swap_ratio_off = 0; +#ifdef CONFIG_MEMPLUS + unsigned long memplus_flag = __get_memplus_swp_flag(swp_entries[0]); + + __memplus_clear_entry(swp_entries[0]); +#endif /* Only single cluster request supported */ WARN_ON_ONCE(n_goal > 1 && size == SWAPFILE_CLUSTER); @@ -1002,6 +1007,14 @@ start_over: spin_unlock(&swap_avail_lock); start: spin_lock(&si->lock); +#ifdef CONFIG_MEMPLUS + if (memplus_enabled() && + (memplus_flag != __memplus_entry(si->flags))) { + spin_lock(&swap_avail_lock); + spin_unlock(&si->lock); + goto nextsi; + } +#endif if (!si->highest_bit || !(si->flags & SWP_WRITEOK)) { spin_lock(&swap_avail_lock); if (plist_node_empty(&si->avail_lists[node])) { diff --git a/mm/vmpressure.c b/mm/vmpressure.c index cf75fcab8a70..9fd1de3c0b52 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -182,6 +182,8 @@ struct vmpressure_event { struct eventfd_ctx *efd; enum vmpressure_levels level; enum vmpressure_modes mode; + unsigned long min; + unsigned long max; struct list_head node; }; @@ -191,6 +193,8 @@ static bool vmpressure_event(struct vmpressure *vmpr, { struct vmpressure_event *ev; bool ret = false; + unsigned long cache = global_node_page_state(NR_INACTIVE_FILE) + + global_node_page_state(NR_ACTIVE_FILE); mutex_lock(&vmpr->events_lock); list_for_each_entry(ev, &vmpr->events, node) { @@ -200,6 +204,8 @@ static bool vmpressure_event(struct vmpressure *vmpr, continue; if (level < ev->level) continue; + if (cache <= ev->min || cache > ev->max) + continue; eventfd_signal(ev->efd, 1); ret = true; } @@ -447,7 +453,7 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio) vmpressure(gfp, memcg, true, vmpressure_win, 0); } -#define MAX_VMPRESSURE_ARGS_LEN (strlen("critical") + strlen("hierarchy") + 2) +#define MAX_VMPRESSURE_ARGS_LEN (strlen("critical") + strlen("hierarchy") + 2 + (6*2+2)) /** * vmpressure_register_event() - Bind vmpressure notifications to an eventfd @@ -477,6 +483,9 @@ int vmpressure_register_event(struct mem_cgroup *memcg, char *spec, *spec_orig; char *token; int ret = 0; + char caches[7] = {0}; + unsigned long min_cache = 0; + unsigned long max_cache = ~0; spec_orig = spec = kstrndup(args, MAX_VMPRESSURE_ARGS_LEN, GFP_KERNEL); if (!spec) { @@ -498,8 +507,33 @@ int vmpressure_register_event(struct mem_cgroup *memcg, if (ret < 0) goto out; mode = ret; + } else + goto parse_end; + + /* Find min cache */ + token = strsep(&spec, ","); + if (token) { + snprintf(caches, ((strlen(token) + 1) > sizeof(caches)) ? + sizeof(caches):(strlen(token) + 1), "%s\n", token); + if (kstrtoul(caches, 10, &min_cache) < 0) { + min_cache = 0; + goto parse_end; + } + } else + goto parse_end; + + /* Find max cache */ + token = strsep(&spec, ","); + if (token) { + snprintf(caches, ((strlen(token) + 1) > sizeof(caches)) ? + sizeof(caches):(strlen(token) + 1), "%s\n", token); + if (kstrtoul(caches, 10, &max_cache) < 0) { + max_cache = ~0; + goto parse_end; + } } +parse_end: ev = kzalloc(sizeof(*ev), GFP_KERNEL); if (!ev) { ret = -ENOMEM; @@ -509,6 +543,8 @@ int vmpressure_register_event(struct mem_cgroup *memcg, ev->efd = eventfd; ev->level = level; ev->mode = mode; + ev->min = min_cache; + ev->max = max_cache; mutex_lock(&vmpr->events_lock); list_add(&ev->node, &vmpr->events); diff --git a/mm/vmscan.c b/mm/vmscan.c index cf077f0a6c55..af72a46b39e1 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -102,6 +102,10 @@ struct scan_control { /* One of the zones is ready for compaction */ unsigned int compaction_ready:1; + #ifdef CONFIG_MEMPLUS + /* 1: swap to zram, 0: swap to file */ + unsigned int swp_bdv_type:1; + #endif /* Allocation order */ s8 order; @@ -173,10 +177,16 @@ 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. @@ -1318,6 +1328,8 @@ static unsigned long shrink_page_list(struct list_head *page_list, page_list)) goto activate_locked; } + memplus_set_private(page, sc->swp_bdv_type); + /* add end */ if (!add_to_swap(page)) { if (!PageTransHuge(page)) goto activate_locked; @@ -1568,6 +1580,77 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, return ret; } +#ifdef CONFIG_MEMPLUS +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; +} + +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, + .swp_bdv_type = 1, + }; + + return coretech_reclaim_pagelist(page_list, vma, &sc); +} + +unsigned long swapout_to_disk(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, + .swp_bdv_type = 0, + }; + + return coretech_reclaim_pagelist(page_list, vma, &sc); +} +#endif + #ifdef CONFIG_PROCESS_RECLAIM unsigned long reclaim_pages_from_list(struct list_head *page_list, struct vm_area_struct *vma) @@ -1758,6 +1841,14 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan, * pages, triggering a premature OOM. */ scan++; + + if (memplus_check_isolate_page(page) && + (BIT(lru) & LRU_ALL_ANON)) { + list_move(&page->lru, src); + continue; + } + /* add end */ + switch (__isolate_lru_page(page, mode)) { case 0: nr_pages = hpage_nr_pages(page); @@ -2107,6 +2198,7 @@ static unsigned move_active_pages_to_lru(struct lruvec *lruvec, page = lru_to_page(list); lruvec = mem_cgroup_page_lruvec(page, pgdat); + memplus_page_to_lru(lru, page); VM_BUG_ON_PAGE(PageLRU(page), page); SetPageLRU(page); @@ -2287,6 +2379,12 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file, if (!file && !total_swap_pages) return false; + if (!file) { + inactive_lru = MEMPLUS_PAGE_LRU; + active_lru = MEMPLUS_PAGE_LRU + LRU_ACTIVE; + } + /* add end */ + inactive = lruvec_lru_size(lruvec, inactive_lru, sc->reclaim_idx); active = lruvec_lru_size(lruvec, active_lru, sc->reclaim_idx); @@ -2358,6 +2456,16 @@ 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 (memplus_enabled()) { + scan_balance = SCAN_EQUAL; + goto out; + } + /* 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; @@ -2512,6 +2620,12 @@ out: if (!scan && !mem_cgroup_online(memcg)) scan = min(size, SWAP_CLUSTER_MAX); + if (memplus_enabled() && + (lru == LRU_INACTIVE_ANON || lru == LRU_ACTIVE_ANON)) { + size = 0; + scan = 0; + } + switch (scan_balance) { case SCAN_EQUAL: /* Scan lists relative to size */ @@ -2583,8 +2697,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc sc->priority == DEF_PRIORITY); blk_start_plug(&plug); - while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || - nr[LRU_INACTIVE_FILE]) { + while (nr[MEMPLUS_PAGE_LRU] || nr[LRU_ACTIVE_FILE] || + nr[LRU_INACTIVE_FILE]) { unsigned long nr_anon, nr_file, percentage; unsigned long nr_scanned; @@ -2611,7 +2725,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc * proportional to the original scan target. */ nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; - nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; + lru = MEMPLUS_PAGE_LRU; + nr_anon = nr[lru] + nr[lru + LRU_ACTIVE]; /* * It's just vindictive to attack the larger once the smaller @@ -2642,7 +2757,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc * Recalculate the other LRU scan count based on its original * scan target and the percentage scanning already complete */ - lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; + + lru = (lru == LRU_FILE) ? MEMPLUS_PAGE_LRU : LRU_FILE; nr_scanned = targets[lru] - nr[lru]; nr[lru] = targets[lru] * (100 - percentage) / 100; nr[lru] -= min(nr[lru], nr_scanned); @@ -2663,7 +2779,7 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc */ if (inactive_list_is_low(lruvec, false, sc, true)) shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); + sc, MEMPLUS_PAGE_LRU + LRU_ACTIVE); } /* Use reclaim/compaction for costly allocs or under memory pressure */ @@ -3434,7 +3550,7 @@ static void age_active_anon(struct pglist_data *pgdat, if (inactive_list_is_low(lruvec, false, sc, true)) shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); + sc, MEMPLUS_PAGE_LRU + LRU_ACTIVE); memcg = mem_cgroup_iter(NULL, memcg, NULL); } while (memcg); diff --git a/mm/vmstat.c b/mm/vmstat.c index bcd2f31ffe7d..a187f3fef239 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1112,6 +1112,10 @@ const char * const vmstat_text[] = { "nr_zone_active_anon", "nr_zone_inactive_file", "nr_zone_active_file", +#ifdef CONFIG_MEMPLUS + "nr_zone_inactive_anon_swpcache", + "nr_zone_active_anon_swpcache", +#endif "nr_zone_unevictable", "nr_zone_write_pending", "nr_mlock", @@ -1123,8 +1127,14 @@ const char * const vmstat_text[] = { "nr_bounce", #if IS_ENABLED(CONFIG_ZSMALLOC) "nr_zspages", +#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 @@ -1141,6 +1151,10 @@ const char * const vmstat_text[] = { "nr_active_anon", "nr_inactive_file", "nr_active_file", +#ifdef CONFIG_MEMPLUS + "nr_inactive_anon_swpcache", + "nr_active_anon_swpcache", +#endif "nr_unevictable", "nr_slab_reclaimable", "nr_slab_unreclaimable", @@ -1296,6 +1310,19 @@ const char * const vmstat_text[] = { "speculative_pgfault_anon", "speculative_pgfault_file", #endif +#ifdef CONFIG_MEMPLUS + "anonfault", + "wpfault", + "swapfault", + "swapmajfault", + "pgcachemiss", + "readfault", + "cowfault", + "sharedfault", + "filemajfault", + "retrypage", + "specretry" +#endif #endif /* CONFIG_VM_EVENT_COUNTERS */ }; #endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */ diff --git a/net/Kconfig b/net/Kconfig index 6870f6c838e5..61efb334b910 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 bdaf53925acd..b43ddcb2eaac 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 496a5ac0e71f..b204a7921539 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 100755 index 000000000000..96f486bf9edc --- /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 100755 index 000000000000..db7ee3df6771 --- /dev/null +++ b/net/opsla/op_sla.c @@ -0,0 +1,1999 @@ +// 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); + int game_rtt_info[2]; +#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; + } else { + memset(game_rtt_info, 0x0, sizeof(game_rtt_info)); + game_rtt_info[0] = game_type; + game_rtt_info[1] = time_now - game_timestamp; + op_sla_send_to_user(SLA_NOTIFY_GAME_RTT, + (char *)game_rtt_info, + sizeof(game_rtt_info)); + } + 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) >= 2000) { + 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\n", + __func__, skb->len, skb->mark, + ntohs(tcp_hdr(skb)->source)); + + 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/opslalib/Makefile b/opslalib/Makefile new file mode 100755 index 000000000000..cb3c6e7ec792 --- /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/scripts/checkpatch.pl b/scripts/checkpatch.pl index f49524e14851..1b4e7730a449 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,10 +2814,10 @@ 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 && - !($line =~ /^\s*[a-zA-Z0-9_\/\.\-\,]+\s+\|\s+\d+/ || + length($line) > 120 && + !($line =~ /^\s*[a-zA-Z0-9_\/\.\-]+\s+\|\s+\d+/ || # file delta changes $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || # filename then : @@ -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/techpack/camera/Makefile b/techpack/camera/Makefile new file mode 100755 index 000000000000..9e0b13785b58 --- /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 100755 index 000000000000..451723eebce3 --- /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 100755 index 000000000000..1a7714018004 --- /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 100755 index 000000000000..9b08bcb80c2b --- /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 100755 index 000000000000..875b95587ab6 --- /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 000000000000..451723eebce3 --- /dev/null +++ b/techpack/camera/config/litocamera.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/litocameraconf.h b/techpack/camera/config/litocameraconf.h new file mode 100755 index 000000000000..1e9df16e8c2f --- /dev/null +++ b/techpack/camera/config/litocameraconf.h @@ -0,0 +1,6 @@ +/* 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/drivers/Makefile b/techpack/camera/drivers/Makefile new file mode 100755 index 000000000000..13edfb587419 --- /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 100755 index 000000000000..323a523011a2 --- /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 100755 index 000000000000..ab12ab52f293 --- /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 100755 index 000000000000..e903dc805ed0 --- /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 100755 index 000000000000..8dcbe8ed1971 --- /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 100755 index 000000000000..0663b8d0f30d --- /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 100755 index 000000000000..94e2f36d0544 --- /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 100755 index 000000000000..3e89b22b1b18 --- /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 100755 index 000000000000..2fb5d5fe97b9 --- /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 100755 index 000000000000..b422b34f244b --- /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 100755 index 000000000000..278dadb18db4 --- /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 100755 index 000000000000..663eca92a5fe --- /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 100755 index 000000000000..193e01be4796 --- /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 100755 index 000000000000..5abca3939338 --- /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 100755 index 000000000000..4a0fbda825c5 --- /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 100755 index 000000000000..e117039fc3ab --- /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 100755 index 000000000000..642d530054d8 --- /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 100755 index 000000000000..2c1c685e76b8 --- /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 100755 index 000000000000..423961aaf2af --- /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 100755 index 000000000000..087fdbf36544 --- /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 100755 index 000000000000..8ee889fcffb9 --- /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 100755 index 000000000000..63e88dd24aea --- /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 100755 index 000000000000..fe074734f389 --- /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 100755 index 000000000000..4fefa2f35db3 --- /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 100755 index 000000000000..062d0213115c --- /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 100755 index 000000000000..1a81a4d59e99 --- /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 100755 index 000000000000..6fc8f9830cec --- /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 100755 index 000000000000..75e6c9c71e65 --- /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 100755 index 000000000000..adbc0d6c3464 --- /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 100755 index 000000000000..0926e6e3d8d1 --- /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 100755 index 000000000000..a1d8b4026059 --- /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 100755 index 000000000000..3b4e4fb25275 --- /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 100755 index 000000000000..503efc20e8b8 --- /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 100755 index 000000000000..de11b7136563 --- /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 100755 index 000000000000..b7f3550bc632 --- /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 100755 index 000000000000..0306b14ef14a --- /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 100755 index 000000000000..7c8d8412656d --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -0,0 +1,700 @@ +// 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; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int reg_base_index; + uint32_t value; + + 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); + } + + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_info = &cpas_hw->soc_info; + reg_base_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + /* Update the ipe_0_rd_qosgen_MainCtl_Low */ + cam_io_w_mb(0x2, soc_info->reg_map[reg_base_index].mem_base + + 0x2208); + /* Update the ipe_0_rd_qosgen_Shaping_Low */ + cam_io_w_mb(0x14141414, soc_info->reg_map[reg_base_index].mem_base + + 0x2220); + /* Update the ipe_0_rd_qosgen_Shaping_High */ + cam_io_w_mb(0x14141414, soc_info->reg_map[reg_base_index].mem_base + + 0x2224); + + /* Update the ipe_1_bps_rd_qosgen_MainCtl_Low */ + cam_io_w_mb(0x2, soc_info->reg_map[reg_base_index].mem_base + + 0x2308); + /* Update the ipe_1_bps_rd_qosgen_Shaping_Low */ + cam_io_w_mb(0x14141414, soc_info->reg_map[reg_base_index].mem_base + + 0x2320); + /* Update the ipe_1_bps_rd_qosgen_Shaping_High */ + cam_io_w_mb(0x14141414, soc_info->reg_map[reg_base_index].mem_base + + 0x2324); + + + /* Dumping the registers values */ + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2208); + + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2220); + + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2224); + + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2308); + + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2320); + + value = cam_io_r_mb(soc_info->reg_map[reg_base_index].mem_base + + 0x2324); + 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 100755 index 000000000000..a4d44a3feff6 --- /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 100755 index 000000000000..2f444710e9f4 --- /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 100755 index 000000000000..df9711e74379 --- /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 100755 index 000000000000..788f571a3a13 --- /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 100755 index 000000000000..aae26b5a9178 --- /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 100755 index 000000000000..7ec9bec36fd1 --- /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 100755 index 000000000000..5844c38ae52c --- /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 100755 index 000000000000..769e77fc3d6b --- /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 100755 index 000000000000..0d46e0ddcc20 --- /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 100755 index 000000000000..7c551dfcf8a5 --- /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 100755 index 000000000000..732b9593c38b --- /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 100755 index 000000000000..7f38392a7d57 --- /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 100755 index 000000000000..91acf1e5ee80 --- /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 100755 index 000000000000..76d4a7d0e17b --- /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 100755 index 000000000000..77ea6badfe94 --- /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 100755 index 000000000000..1e0917637b8e --- /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 100755 index 000000000000..ab36c8862888 --- /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 100755 index 000000000000..a55bb002ffc2 --- /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 100755 index 000000000000..be472372aeb0 --- /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 100755 index 000000000000..f0c086ccab18 --- /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 100755 index 000000000000..4895219ffd06 --- /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 100755 index 000000000000..9ac5da25571e --- /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 100755 index 000000000000..d27d578f6c8d --- /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 100755 index 000000000000..bd7d65913649 --- /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 100755 index 000000000000..1da630ed5ec2 --- /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 100755 index 000000000000..9011ac9d5291 --- /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 100755 index 000000000000..e9c95d43d366 --- /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 100755 index 000000000000..1db06bb3ab1f --- /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 100755 index 000000000000..64f4555528bf --- /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 100755 index 000000000000..0fd557c14052 --- /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 100755 index 000000000000..b1fb1cb42913 --- /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 100755 index 000000000000..92356a35d8c8 --- /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 100755 index 000000000000..ec6468f85dc0 --- /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 100755 index 000000000000..ab0fa92b43f2 --- /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 100755 index 000000000000..c92cea8fc9e9 --- /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 100755 index 000000000000..8db8097679b5 --- /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 100755 index 000000000000..b33dfa699647 --- /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 100755 index 000000000000..49bc5bbc1b07 --- /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 100755 index 000000000000..81ed464e400a --- /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 100755 index 000000000000..6a53cc67f7e6 --- /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 100755 index 000000000000..c28fcdf3efc6 --- /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 100755 index 000000000000..1f8815e72f20 --- /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 100755 index 000000000000..3498e6235279 --- /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 100755 index 000000000000..e35e5e520b7b --- /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 100755 index 000000000000..c3d5a68c6910 --- /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 100755 index 000000000000..b27ce09e36e6 --- /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 100755 index 000000000000..ad1fb0bc5737 --- /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 100755 index 000000000000..f3eedeb3b811 --- /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 100755 index 000000000000..0c81cb642930 --- /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 100755 index 000000000000..aec65fc06f4b --- /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 100755 index 000000000000..180ea7152a76 --- /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 100755 index 000000000000..edd8bd5617c9 --- /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 100755 index 000000000000..bdb2ed5f900b --- /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 100755 index 000000000000..afd42d23b9fb --- /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 100755 index 000000000000..df4ae01d7ef2 --- /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 100755 index 000000000000..9ba7803d4f44 --- /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 100755 index 000000000000..a4f19bf404a5 --- /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 100755 index 000000000000..c03aa58bb8f3 --- /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 100755 index 000000000000..68b36f706604 --- /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 100755 index 000000000000..9c3aac09a137 --- /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 100755 index 000000000000..e4cb645b7af0 --- /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 100755 index 000000000000..6c46b3ac8784 --- /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 100755 index 000000000000..b4f33d3e4dd3 --- /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 100755 index 000000000000..d0629612193a --- /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 100755 index 000000000000..480364df1fd6 --- /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 100755 index 000000000000..491e6a16492b --- /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 100755 index 000000000000..8a079bd14202 --- /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 100755 index 000000000000..162c5e65530c --- /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 100755 index 000000000000..a80c27325b72 --- /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 100755 index 000000000000..481eeafdb0b2 --- /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 100755 index 000000000000..da4feac909e4 --- /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 100755 index 000000000000..b87d5dba817a --- /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 100755 index 000000000000..9b47ac37349a --- /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 100755 index 000000000000..b118471823cd --- /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 100755 index 000000000000..af80a2eac15d --- /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 100755 index 000000000000..f2628e41640b --- /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 100755 index 000000000000..80a724b53d94 --- /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 100755 index 000000000000..ea14ee623fb3 --- /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 100755 index 000000000000..d87c7ef238df --- /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 100755 index 000000000000..d57373c332e0 --- /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 100755 index 000000000000..4263cf7ea669 --- /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 100755 index 000000000000..1a15e9233896 --- /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 100755 index 000000000000..0390488d92b3 --- /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 100755 index 000000000000..11cc7f7a3317 --- /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 100755 index 000000000000..8981b18823ad --- /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 100755 index 000000000000..86ad96d61cb7 --- /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 000000000000..8ee6f693a808 --- /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 100755 index 000000000000..503e46526dee --- /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 100755 index 000000000000..9c3f33181ae6 --- /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 100755 index 000000000000..cf9140eb8c88 --- /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 100755 index 000000000000..33b808c934e3 --- /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 100755 index 000000000000..daa4c8ed6c73 --- /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(30)); + 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 100755 index 000000000000..7e6b91bab916 --- /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 100755 index 000000000000..b1567d6b9cd8 --- /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 100755 index 000000000000..69e24bcc8625 --- /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 100755 index 000000000000..ccdfc05f103d --- /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 100755 index 000000000000..86a14229915f --- /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 100755 index 000000000000..356c9a0a8919 --- /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 100755 index 000000000000..c9bd4c4430e9 --- /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 100755 index 000000000000..22beb49ef6fc --- /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 100755 index 000000000000..fb595fe8f02a --- /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 100755 index 000000000000..cc1fe18e05fd --- /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 100755 index 000000000000..8fa0e951b714 --- /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 100755 index 000000000000..6d5d0fd61c88 --- /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 100755 index 000000000000..41c244c96572 --- /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 100755 index 000000000000..8ccd9f0b3f62 --- /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 100755 index 000000000000..714fa8ef2b31 --- /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 100755 index 000000000000..70f96ea416d8 --- /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 100755 index 000000000000..612379ec4bdd --- /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 100755 index 000000000000..d88347caa388 --- /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 100755 index 000000000000..66c1b32d51b0 --- /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 100755 index 000000000000..75cd32a0cd60 --- /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 100755 index 000000000000..4c2ac18089af --- /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 100755 index 000000000000..eca0e43a9b5e --- /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 100755 index 000000000000..1f8e4d05b74b --- /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 100755 index 000000000000..07d555b17009 --- /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 100755 index 000000000000..4d8783ce0c0f --- /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 100755 index 000000000000..b77f2dfa350e --- /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 100755 index 000000000000..7abcc64068ee --- /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 100755 index 000000000000..4f76d084fba3 --- /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 100755 index 000000000000..56ce59636dda --- /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 100755 index 000000000000..7ac79feb2a9f --- /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 100755 index 000000000000..a1d1c6a60881 --- /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 100755 index 000000000000..1609a7a04808 --- /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 100755 index 000000000000..11d6a602117c --- /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 100755 index 000000000000..43afd0377057 --- /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 100755 index 000000000000..362d513c6a8f --- /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 100755 index 000000000000..c2d78b69c684 --- /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 100755 index 000000000000..77e2a059af57 --- /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 100755 index 000000000000..64d9de084ec1 --- /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 100755 index 000000000000..e129ea6999b0 --- /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 100755 index 000000000000..5336352a4797 --- /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 100755 index 000000000000..663bc247b27f --- /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 100755 index 000000000000..6823b6386b91 --- /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 100755 index 000000000000..8acd77d1f1e2 --- /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 100755 index 000000000000..ae65df7c1126 --- /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 100755 index 000000000000..aab38c791637 --- /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 100755 index 000000000000..c19ade50bec9 --- /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 100755 index 000000000000..d5ab83c81dd7 --- /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 100755 index 000000000000..2b902d753ad2 --- /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 100755 index 000000000000..314ebff70fc0 --- /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 100755 index 000000000000..19cc86496371 --- /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 100755 index 000000000000..2783ddccf2d8 --- /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 100755 index 000000000000..9094f1409a66 --- /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 100755 index 000000000000..cac3adf65a93 --- /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 100755 index 000000000000..cae125315895 --- /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 100755 index 000000000000..c5b4ab69fa9f --- /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 100755 index 000000000000..97336a2da3b8 --- /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 100755 index 000000000000..2ab4651e4271 --- /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 100755 index 000000000000..9ea8d74a35ca --- /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 100755 index 000000000000..7813e55f508b --- /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 100755 index 000000000000..bfb17d2145f8 --- /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 100755 index 000000000000..54a38bdf41ca --- /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 100755 index 000000000000..0ed1c6ede3ce --- /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 100755 index 000000000000..f071a0627bbc --- /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 100755 index 000000000000..e125bbb235d8 --- /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 100755 index 000000000000..40d8e40ae852 --- /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 100755 index 000000000000..98c84ad77d93 --- /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 100755 index 000000000000..6974a568fd6c --- /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 100755 index 000000000000..7aaacde775f4 --- /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 100755 index 000000000000..c570e84a011c --- /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 100755 index 000000000000..077f89060bca --- /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 100755 index 000000000000..2eae53205c8c --- /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 100755 index 000000000000..03be713e6068 --- /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 100755 index 000000000000..c5225c540722 --- /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 100755 index 000000000000..961bf954aaa1 --- /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 100755 index 000000000000..2bd393fc97a8 --- /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 100755 index 000000000000..14c96097cdf6 --- /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 100755 index 000000000000..932cab858a70 --- /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 100755 index 000000000000..471f870e4c73 --- /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 100755 index 000000000000..b16a9dfed011 --- /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 100755 index 000000000000..3a11865a6051 --- /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 100755 index 000000000000..0a68ce997283 --- /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 100755 index 000000000000..4961527de1a7 --- /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 100755 index 000000000000..f189bd13a244 --- /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 100755 index 000000000000..09b4b8d3e0f6 --- /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 100755 index 000000000000..e482c11a82bd --- /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 100755 index 000000000000..1b93547fdf25 --- /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 100755 index 000000000000..30c51f7cfcfd --- /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 100755 index 000000000000..f0162f98833a --- /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 100755 index 000000000000..1304bbc71d38 --- /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 100755 index 000000000000..dc3a1c13fe82 --- /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 100755 index 000000000000..ce82c5e799c5 --- /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 100755 index 000000000000..9dda8f284c35 --- /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 100755 index 000000000000..a0c07489ee77 --- /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 100755 index 000000000000..159c54bbed0c --- /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 100755 index 000000000000..e610a9e7ee03 --- /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 100755 index 000000000000..4830bf58e89e --- /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 100755 index 000000000000..df9341c90c77 --- /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 100755 index 000000000000..8eb8ec367850 --- /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 100755 index 000000000000..4a5d9e0a9b60 --- /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 100755 index 000000000000..e0fb0103de75 --- /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 100755 index 000000000000..72cdba4da04c --- /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 100755 index 000000000000..fa544c7a089e --- /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 100755 index 000000000000..9fb88ed85f1b --- /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 100755 index 000000000000..7c09f2b435f5 --- /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 100755 index 000000000000..3387c3d0f062 --- /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 100755 index 000000000000..40700bbce9e0 --- /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 100755 index 000000000000..bc77e726d3e6 --- /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 100755 index 000000000000..df6ea0eac798 --- /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 100755 index 000000000000..8df30c0f44de --- /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 100755 index 000000000000..b736708fa99d --- /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 100755 index 000000000000..accb5a8b5827 --- /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 100755 index 000000000000..4e2609648b30 --- /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 100755 index 000000000000..b74d53700419 --- /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 100755 index 000000000000..17eb25b0facf --- /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 100755 index 000000000000..5ef984cba883 --- /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 100755 index 000000000000..d77ac2bfdb63 --- /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 100755 index 000000000000..50599d879255 --- /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 100755 index 000000000000..eef1583451ba --- /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 100755 index 000000000000..6ce30db66fe3 --- /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 100755 index 000000000000..e216a46a3a6f --- /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 100755 index 000000000000..ea1515bb22c6 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -0,0 +1,3938 @@ +// 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, + (long long)req_id, + 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 100755 index 000000000000..3f2b6d4aea28 --- /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 6 + +#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 100755 index 000000000000..fbaa7de494f7 --- /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 100755 index 000000000000..6b428c41c1b0 --- /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 100755 index 000000000000..dc72c522d140 --- /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 000000000000..c77840137484 --- /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 100755 index 000000000000..48ad09ce5ee2 --- /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 100755 index 000000000000..68ab7917e947 --- /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 100755 index 000000000000..ba44534fa48d --- /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 100755 index 000000000000..be200f1b2693 --- /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 100755 index 000000000000..88b6bf079e9c --- /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 100755 index 000000000000..c0e339eedd9b --- /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 100755 index 000000000000..075f5c34702d --- /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 100755 index 000000000000..29d98503f305 --- /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 100755 index 000000000000..f938710b69ae --- /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 100755 index 000000000000..385643d5e532 --- /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 100755 index 000000000000..6925b3aba80f --- /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 100755 index 000000000000..e61c6eeba3c0 --- /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 000000000000..a174d67766c3 --- /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 100755 index 000000000000..e5636f26ce36 --- /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 100755 index 000000000000..46bd99fc9e29 --- /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 000000000000..be6f8dd994ed --- /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 100755 index 000000000000..3ee629e3f1ca --- /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 100755 index 000000000000..65b4fb99fa03 --- /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 100755 index 000000000000..a1301bf41d5d --- /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 100755 index 000000000000..2ea59a083f85 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -0,0 +1,1952 @@ +// 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]); + reinit_completion(&cci_dev->cci_master_info[master].report_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]); + + reinit_completion(&cci_dev->cci_master_info[master].report_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); + + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); + /* + * 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].rd_done); + 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) +{ + uint8_t rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + + rc = cam_cci_soc_release(cci_dev); + 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); + 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; + + 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); + 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 100755 index 000000000000..739fd303b236 --- /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 000000000000..a03df823f27c --- /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 100755 index 000000000000..4852d199a272 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -0,0 +1,553 @@ +// 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]); + } + 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]); + } + 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]); + } + 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]); + } + 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_DEVNODE | 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 100755 index 000000000000..d65f5e5fd271 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -0,0 +1,303 @@ +/* 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_MASTERS 2 +#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 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; +}; + +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 + * @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[NUM_MASTERS][NUM_QUEUES]; + struct cam_cci_master_info cci_master_info[NUM_MASTERS]; + enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS]; + 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 100755 index 000000000000..73756a301f7a --- /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 100755 index 000000000000..ff74be5eb9f9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -0,0 +1,420 @@ +// 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" + +int cam_cci_init(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + uint8_t i = 0, j = 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 (cci_dev->ref_count++) { + CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); + CAM_DBG(CAM_CCI, "master %d", master); + if (master < MASTER_MAX && master >= 0) { + mutex_lock(&cci_dev->cci_master_info[master].mutex); + flush_workqueue(cci_dev->write_wq[master]); + /* Re-initialize the completion */ + reinit_completion( + &cci_dev->cci_master_info[master].reset_complete); + reinit_completion( + &cci_dev->cci_master_info[master].rd_done); + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + /* 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 */ + 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; + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + } + return 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_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 != 0) + CAM_ERR(CAM_CCI, "CPAS start failed"); + + cam_cci_get_clk_rates(cci_dev, c_ctrl); + + /* Re-initialize the completion */ + reinit_completion(&cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + + /* 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; + + for (i = 0; i < NUM_MASTERS; i++) { + for (j = 0; j < NUM_QUEUES; j++) { + if (j == QUEUE_0) + cci_dev->cci_i2c_queue_info[i][j].max_queue_size + = CCI_I2C_QUEUE_0_SIZE; + else + cci_dev->cci_i2c_queue_info[i][j].max_queue_size + = CCI_I2C_QUEUE_1_SIZE; + + CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, + cci_dev->cci_i2c_queue_info[i][j].max_queue_size, + cci_dev->cci_i2c_queue_info[i][j].max_queue_size); + } + } + + cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; + cam_io_w_mb(CCI_RESET_CMD_RMSK, base + + CCI_RESET_CMD_ADDR); + cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) { + CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); + if (rc == 0) + rc = -ETIMEDOUT; + 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); + + for (i = 0; i < MASTER_MAX; i++) { + if (!cci_dev->write_wq[i]) { + CAM_ERR(CAM_CCI, "Failed to flush write wq"); + rc = -ENOMEM; + goto reset_complete_failed; + } else { + flush_workqueue(cci_dev->write_wq[i]); + } + } + + /* 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 < NUM_MASTERS; i++) { + new_cci_dev->cci_master_info[i].status = 0; + new_cci_dev->cci_master_info[i].is_first_req = true; + 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) +{ + 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) { + CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d", + cci_dev->ref_count, cci_dev->cci_state); + return -EINVAL; + } + if (--cci_dev->ref_count) { + CAM_DBG(CAM_CCI, "ref_count Exit %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]); + + for (i = 0; i < MASTER_MAX; 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 100755 index 000000000000..f0cdfe822cd3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, 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); + +/** + * @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 100755 index 000000000000..d98b84574363 --- /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 100755 index 000000000000..7af2a7a3d26b --- /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 100755 index 000000000000..237fa787f226 --- /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 100755 index 000000000000..ba98d9adcc2d --- /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 100755 index 000000000000..78c7a848cd81 --- /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 100755 index 000000000000..c5a8033aaffb --- /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 100755 index 000000000000..c02b9556add4 --- /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 100755 index 000000000000..e910162858b3 --- /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 100755 index 000000000000..30b61067a792 --- /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 100755 index 000000000000..32fbf47eabd9 --- /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 100755 index 000000000000..3bed231e0246 --- /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 100755 index 000000000000..cbd0dc582b32 --- /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 100755 index 000000000000..7a676c1135a0 --- /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 000000000000..ae2035115c89 --- /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 100755 index 000000000000..6a1e867542cb --- /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 100755 index 000000000000..328541553b59 --- /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 100755 index 000000000000..66f8aaddc958 --- /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 100755 index 000000000000..33f80b0c9716 --- /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 100755 index 000000000000..ed37989eb2d7 --- /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 100755 index 000000000000..da9e9e1b19cb --- /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 100755 index 000000000000..f4dc655045a4 --- /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 100755 index 000000000000..c382809dbb92 --- /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 100755 index 000000000000..5eccfd8aa11b --- /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 100755 index 000000000000..29e352e47ce9 --- /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 100755 index 000000000000..762977f4b968 --- /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 100755 index 000000000000..cfe7c3464f64 --- /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 100755 index 000000000000..948f297a1e77 --- /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 000000000000..3afb104b23e7 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -0,0 +1,1105 @@ +// 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); + } + if(o_ctrl->cam_ois_download_fw_in_advance) { + 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)); + } + 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; + + 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; + if(o_ctrl->cam_ois_download_fw_in_advance){ + 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); + } else { + rc = cam_ois_fw_download(o_ctrl); + } + + if (rc) { + if(o_ctrl->cam_ois_download_fw_in_advance){ + o_ctrl->ois_download_fw_done = CAM_OIS_FW_NOT_DOWNLOAD; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + } + CAM_ERR(CAM_OIS, "Failed OIS FW Download"); + goto pwr_dwn; + } + if(o_ctrl->cam_ois_download_fw_in_advance){ + o_ctrl->ois_download_fw_done = CAM_OIS_FW_DOWNLOAD_DONE; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + } + } + + 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"); + } + 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: + if(o_ctrl->cam_ois_download_fw_in_advance){ + 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)); + } + 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: + if(o_ctrl->cam_ois_download_fw_in_advance){ + 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)); + } + 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: + if(o_ctrl->cam_ois_download_fw_in_advance){ + 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)); + } + 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: + if(o_ctrl->cam_ois_download_fw_in_advance){ + 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)); + } + 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 000000000000..685bd200b079 --- /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 000000000000..20b4fd27b36b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -0,0 +1,529 @@ +// 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" +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; +} + +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; + 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; + 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)); + if(o_ctrl->cam_ois_download_fw_in_advance){ + //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)); + } + 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)); + 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; +#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 000000000000..af31da61b871 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -0,0 +1,220 @@ +/* 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 + +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, +}; + + +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 + 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; + int cam_ois_download_fw_in_advance; +}; + +#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 000000000000..cda0ab3119ce --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -0,0 +1,196 @@ +// 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); + } + + ret = of_property_read_u32(of_node, "download,fw", &id); + if (ret) { + o_ctrl->cam_ois_download_fw_in_advance = 0; + CAM_ERR(CAM_OIS, "get download,fw failed rc:%d, default %d", ret, o_ctrl->cam_ois_download_fw_in_advance); + } else { + o_ctrl->cam_ois_download_fw_in_advance = (uint8_t)id; + CAM_INFO(CAM_OIS, "read download,fw success, value:%d", o_ctrl->cam_ois_download_fw_in_advance); + } + + 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 100755 index 000000000000..fd2c209c7504 --- /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 100755 index 000000000000..5094b299419c --- /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 100755 index 000000000000..2d9451c57d82 --- /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 000000000000..97c3579f9129 --- /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 000000000000..a02766bccb87 --- /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 000000000000..e549c794b52e --- /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 000000000000..bcb045f72948 --- /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 000000000000..5a70068b2049 --- /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 000000000000..b9818a992787 --- /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 100755 index 000000000000..e132575c5611 --- /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 000000000000..32daf1a02c04 --- /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 000000000000..870d4b9c7dcd --- /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 000000000000..8a8e97c3f25d --- /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 000000000000..1be0fc28a825 --- /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 100755 index 000000000000..94dab4eaa1d0 --- /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 000000000000..b2f91f7cd227 --- /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 000000000000..3042fa2ee621 --- /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 000000000000..e0ca8e5df9b4 --- /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 000000000000..5c814c3da1c7 --- /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 000000000000..59b87312d271 --- /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 000000000000..8339f8fd1ced --- /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 000000000000..c9b23ee2dd9d --- /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 000000000000..e5c1ed52fdbe --- /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 000000000000..942df7bf77b5 --- /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 000000000000..fff623dd9709 --- /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 000000000000..11bf5864b909 --- /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 000000000000..556106ff13e7 --- /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 000000000000..aff2022b69a0 --- /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 000000000000..2f4963060d65 --- /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 000000000000..55048758543d --- /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 100755 index 000000000000..48a93b1c222b --- /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 000000000000..a8a7a0f9cfd4 --- /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 000000000000..fc4b7c24e08f --- /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 000000000000..a23413597079 --- /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 000000000000..6e2286ec14e6 --- /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 000000000000..66bab2fc6b84 --- /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 000000000000..c43e8bac7a78 --- /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 000000000000..fa8ee0616bca --- /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 000000000000..9c07f2e42c5b --- /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 000000000000..ce4dea68439d --- /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 000000000000..6a03e5b1b592 --- /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 000000000000..41e3316cc4aa --- /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 000000000000..df96747aa31b --- /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 000000000000..fb86e0c6dac6 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.c @@ -0,0 +1,1568 @@ +#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 +static struct kobject *cam_ois_kobj; +bool dump_ois_registers = false; +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; +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; +} + +static ssize_t dump_registers_store(struct device * dev, + struct device_attribute * attr, + const char * buf, + size_t count) +{ + unsigned int if_start_thread; + CAM_WARN(CAM_OIS, "%s", buf); + if (sscanf(buf, "%u", &if_start_thread) != 1) { + return -1; + } + if(if_start_thread) { + dump_ois_registers = true; + } else { + dump_ois_registers = false; + } + + return count; +} + +static DEVICE_ATTR(dump_registers, 0644, NULL, dump_registers_store); +static struct attribute *ois_node_attrs[] = { + &dev_attr_dump_registers.attr, + NULL, +}; +static const struct attribute_group ois_common_group = { + .attrs = ois_node_attrs, +}; +static const struct attribute_group *ois_groups[] = { + &ois_common_group, + NULL, +}; + +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]); + } + 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 %ld 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 %ld 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) +{ + int rc; + 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(cam_ois_kobj == NULL){ + cam_ois_kobj = kobject_create_and_add("ois_control", kernel_kobj); + rc = sysfs_create_groups(cam_ois_kobj, ois_groups); + if (rc != 0) { + CAM_ERR(CAM_OIS,"Error creating sysfs ois group"); + sysfs_remove_groups(cam_ois_kobj, ois_groups); + } + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + } + + //Create OIS control node + if(face_common_dir == NULL){ + 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; + } + } + + if(proc_file_entry == NULL){ + 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"); + } + } + + if(proc_file_entry_tele == NULL){ + 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 000000000000..99deda4ef277 --- /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 100755 index 000000000000..1c8ccb0e3bf4 --- /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 100755 index 000000000000..c87540f7950f --- /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 100755 index 000000000000..e259ba7f2c78 --- /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 100755 index 000000000000..48611f6fbd7e --- /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_GC5035_SPC_SENSOR_SETTINGS.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/CAM_GC5035_SPC_SENSOR_SETTINGS.h new file mode 100755 index 000000000000..0097b0efcb28 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/CAM_GC5035_SPC_SENSOR_SETTINGS.h @@ -0,0 +1,128 @@ +/******************** GC5035_OTP_EDIT_START*******************/ +/*index 0 otp read init setting*/ +{ + .reg_setting = + { + {.reg_addr = 0xfc, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf4, .reg_data = 0x40, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf5, .reg_data = 0xe9, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf6, .reg_data = 0x14, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf8, .reg_data = 0x49, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf9, .reg_data = 0x82, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfa, .reg_data = 0x10, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfc, .reg_data = 0x81, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x36, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xd3, .reg_data = 0x87, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x36, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf7, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfc, .reg_data = 0x8f, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfc, .reg_data = 0x8f, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x55, .reg_data = 0x84, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x65, .reg_data = 0x7e, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x66, .reg_data = 0x03, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0xc0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x68, .reg_data = 0x11, .delay = 0, .data_mask = 0x0}, + }, + .size = 22, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/*index 1 dpc page 0*/ +{ + .reg_setting = + { + {.reg_addr = 0xe0, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0xf0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf3, .reg_data = 0x10, .delay = 0, .data_mask = 0x0}, + }, + .size = 3, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/*index 2 close read*/ +{ + .reg_setting = + { + {.reg_addr = 0x67, .reg_data = 0xc0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf3, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + }, + .size = 2, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/*index 3 dpc update setting1*/ +{ + .reg_setting = + { + {.reg_addr = 0xfa, .reg_data = 0x10, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0xc0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xbe, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xa9, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x09, .reg_data = 0x33, .delay = 0, .data_mask = 0x0}, + }, + .size = 6, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0, +}, +/*index 4 dpc update setting2*/ +{ + .reg_setting = + { + {.reg_addr = 0x03, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x04, .reg_data = 0x80, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x95, .reg_data = 0x0a, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x96, .reg_data = 0x30, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x97, .reg_data = 0x0a, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x98, .reg_data = 0x32, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x99, .reg_data = 0x07, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x9a, .reg_data = 0xa9, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf3, .reg_data = 0x80, .delay = 10000, .data_mask = 0x0}, + {.reg_addr = 0xbe, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x09, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x80, .reg_data = 0x02, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xfa, .reg_data = 0x00, .delay = 0, .data_mask = 0x0}, + }, + .size = 17, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/*index 5 reg update page 8*/ +{ + .reg_setting = + { + {.reg_addr = 0xe0, .reg_data = 0x08, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0xf0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf3, .reg_data = 0x10, .delay = 0, .data_mask = 0x0}, + }, + .size = 3, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/*index 6 reg update page 9*/ +{ + .reg_setting = + { + {.reg_addr = 0xe0, .reg_data = 0x09, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0x67, .reg_data = 0xf0, .delay = 0, .data_mask = 0x0}, + {.reg_addr = 0xf3, .reg_data = 0x10, .delay = 0, .data_mask = 0x0}, + }, + .size = 3, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +/******************** GC5035_OTP_EDIT_END*******************/ 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 000000000000..b4ab16b17389 --- /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 100755 index 000000000000..d3a6fbb6c3e4 --- /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 000000000000..49e15221a704 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -0,0 +1,1958 @@ +// 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" }, +}; + + +/******************** GC5035_OTP_EDIT_END*******************/ +struct cam_sensor_dpc_reg_setting_array { + struct cam_sensor_i2c_reg_array reg_setting[25]; + unsigned short size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct cam_sensor_dpc_reg_setting_array gc5035OTPWrite_setting[7] = { +#include "CAM_GC5035_SPC_SENSOR_SETTINGS.h" +}; + +uint32_t totalDpcNum = 0; +uint32_t totalDpcFlag = 0; +uint32_t gc5035_chipversion_buffer[26]={0}; + +static int sensor_gc5035_get_dpc_data(struct cam_sensor_ctrl_t * s_ctrl) +{ + int rc = 0; + uint32_t gc5035_dpcinfo[3] = {0}; + uint32_t i; + uint32_t dpcinfoOffet = 0xcd; + uint32_t chipPage8Offet = 0xd0; + uint32_t chipPage9Offet = 0xc0; + + struct cam_sensor_i2c_reg_setting sensor_setting; + /*write otp read init settings*/ + sensor_setting.reg_setting = gc5035OTPWrite_setting[0].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[0].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[0].data_type; + sensor_setting.size = gc5035OTPWrite_setting[0].size; + sensor_setting.delay = gc5035OTPWrite_setting[0].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + /*write dpc page0 setting*/ + sensor_setting.reg_setting = gc5035OTPWrite_setting[1].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[1].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[1].data_type; + sensor_setting.size = gc5035OTPWrite_setting[1].size; + sensor_setting.delay = gc5035OTPWrite_setting[1].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + + /*read dpc data*/ + for (i = 0; i < 3; i++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + dpcinfoOffet + i, + &gc5035_dpcinfo[i], CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to read dpc info sensor setting"); + break; + } + CAM_ERR(CAM_SENSOR, "info i=%d addr=0x%x data=0x%x",i,dpcinfoOffet + i,gc5035_dpcinfo[i]); + } + + if (rc < 0) + return rc; + /*close read data*/ + sensor_setting.reg_setting = gc5035OTPWrite_setting[2].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[2].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[2].data_type; + sensor_setting.size = gc5035OTPWrite_setting[2].size; + sensor_setting.delay = gc5035OTPWrite_setting[2].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + + for (i = 0; i < 19; i++) { + CAM_DBG(CAM_SENSOR, "gc5035SpcWrite_setting gc5035_dpcinfo[%d] = %x",i,gc5035_dpcinfo[i]); + } + if (gc5035_dpcinfo[0] == 1) { + totalDpcFlag = 1; + totalDpcNum = gc5035_dpcinfo[1] + gc5035_dpcinfo[2] ; + CAM_INFO(CAM_SENSOR, "gc5035SpcWrite_setting gc5035_dpcinfo[1] = %d",gc5035_dpcinfo[1]); + CAM_INFO(CAM_SENSOR, "gc5035SpcWrite_setting gc5035_dpcinfo[2] = %d",gc5035_dpcinfo[2]); + CAM_INFO(CAM_SENSOR, "gc5035SpcWrite_setting totalDpcNum = %d",totalDpcNum); + + } + //write for update reg for page 8 + sensor_setting.reg_setting = gc5035OTPWrite_setting[5].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[5].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[5].data_type; + sensor_setting.size = gc5035OTPWrite_setting[5].size; + sensor_setting.delay = gc5035OTPWrite_setting[5].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + for (i = 0; i < 0x10; i++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + chipPage8Offet + i, + &gc5035_chipversion_buffer[i], CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to read dpc info sensor setting"); + break; + } + } + /*close read data*/ + sensor_setting.reg_setting = gc5035OTPWrite_setting[2].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[2].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[2].data_type; + sensor_setting.size = gc5035OTPWrite_setting[2].size; + sensor_setting.delay = gc5035OTPWrite_setting[2].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + //write for update reg for page 9 + sensor_setting.reg_setting = gc5035OTPWrite_setting[6].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[6].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[6].data_type; + sensor_setting.size = gc5035OTPWrite_setting[6].size; + sensor_setting.delay = gc5035OTPWrite_setting[6].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + for (i = 0x00; i < 0x0a; i++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + chipPage9Offet + i, + &gc5035_chipversion_buffer[0x10+i], CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to read dpc info sensor setting"); + break; + } + } + /*close read data*/ + sensor_setting.reg_setting = gc5035OTPWrite_setting[2].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[2].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[2].data_type; + sensor_setting.size = gc5035OTPWrite_setting[2].size; + sensor_setting.delay = gc5035OTPWrite_setting[2].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + CAM_INFO(CAM_SENSOR, "gc5035S get dpc setting success"); + return rc; + +} + +static int sensor_gc5035_write_dpc_data(struct cam_sensor_ctrl_t * s_ctrl) +{ + int rc = 0; + struct cam_sensor_i2c_reg_array gc5035SpcTotalNum_setting[2]; + struct cam_sensor_i2c_reg_setting sensor_setting; + /*for test + struct cam_sensor_i2c_reg_array gc5035SRAM_setting; + uint32_t temp_val[4]; + int j,i;*/ + + if (totalDpcFlag == 0) + return 0; + + sensor_setting.reg_setting = gc5035OTPWrite_setting[3].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[3].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[3].data_type; + sensor_setting.size = gc5035OTPWrite_setting[3].size; + sensor_setting.delay = gc5035OTPWrite_setting[3].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + gc5035SpcTotalNum_setting[0].reg_addr = 0x01; + gc5035SpcTotalNum_setting[0].reg_data = (totalDpcNum >> 8) & 0x07; + gc5035SpcTotalNum_setting[0].delay = gc5035SpcTotalNum_setting[0].data_mask = 0; + + gc5035SpcTotalNum_setting[1].reg_addr = 0x02; + gc5035SpcTotalNum_setting[1].reg_data = totalDpcNum & 0xff; + gc5035SpcTotalNum_setting[1].delay = gc5035SpcTotalNum_setting[1].data_mask = 0; + + sensor_setting.reg_setting = gc5035SpcTotalNum_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = 2; + sensor_setting.delay = 0; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + + sensor_setting.reg_setting = gc5035OTPWrite_setting[4].reg_setting; + sensor_setting.addr_type = gc5035OTPWrite_setting[4].addr_type; + sensor_setting.data_type = gc5035OTPWrite_setting[4].data_type; + sensor_setting.size = gc5035OTPWrite_setting[4].size; + sensor_setting.delay = gc5035OTPWrite_setting[4].delay; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + CAM_INFO(CAM_SENSOR, "gc5035SpcWrite_setting write sensor setting success"); + /*for test + gc5035SpcTotalNum_setting[0].reg_addr = 0xfe; + gc5035SpcTotalNum_setting[0].reg_data = 0x02; + gc5035SpcTotalNum_setting[0].delay = gc5035SpcTotalNum_setting[0].data_mask = 0; + + gc5035SpcTotalNum_setting[1].reg_addr = 0xbe; + gc5035SpcTotalNum_setting[1].reg_data = 0x00; + gc5035SpcTotalNum_setting[1].delay = gc5035SpcTotalNum_setting[1].data_mask = 0; + + sensor_setting.reg_setting = gc5035SpcTotalNum_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = 2; + sensor_setting.delay = 0; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + for (i=0; i<totalDpcNum*4; i++) { + gc5035SRAM_setting.reg_addr = 0xaa; + gc5035SRAM_setting.reg_data = i; + gc5035SRAM_setting.delay = gc5035SRAM_setting.data_mask = 0; + sensor_setting.reg_setting = &gc5035SRAM_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = 1; + sensor_setting.delay = 0; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + for (j=0; j<4; j++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + 0xac, + &temp_val[j], CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to read dpc info sensor setting"); + break; + } + } + CAM_ERR(CAM_SENSOR,"GC5035_OTP_GC val0 = 0x%x , val1 = 0x%x , val2 = 0x%x,val3 = 0x%x \n", + temp_val[0],temp_val[1],temp_val[2],temp_val[3]); + CAM_ERR(CAM_SENSOR,"GC5035_OTP_GC x = %d , y = %d ,type = %d \n", + ((temp_val[1]&0x0f)<<8) + temp_val[0],((temp_val[2]&0x7f)<<4) + ((temp_val[1]&0xf0)>>4),(((temp_val[3]&0x01)<<1)+((temp_val[2]&0x80)>>7))); + } + + gc5035SpcTotalNum_setting[0].reg_addr = 0xbe; + gc5035SpcTotalNum_setting[0].reg_data = 0x01; + gc5035SpcTotalNum_setting[0].delay = gc5035SpcTotalNum_setting[0].data_mask = 0; + + gc5035SpcTotalNum_setting[1].reg_addr = 0xfe; + gc5035SpcTotalNum_setting[1].reg_data = 0x00; + gc5035SpcTotalNum_setting[1].delay = gc5035SpcTotalNum_setting[1].data_mask = 0; + + sensor_setting.reg_setting = gc5035SpcTotalNum_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = 2; + sensor_setting.delay = 0; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + */ + return rc; +} + +static int sensor_gc5035_update_reg(struct cam_sensor_ctrl_t * s_ctrl) +{ + int rc = -1; + uint8_t flag_chipv = 0; + int i = 0; + uint8_t VALID_FLAG = 0x01; + uint8_t CHIPV_FLAG_OFFSET = 0x0; + uint8_t CHIPV_OFFSET = 0x01; + uint8_t reg_setting_size = 0; + struct cam_sensor_i2c_reg_array gc5035_update_reg_setting[20]; + struct cam_sensor_i2c_reg_setting sensor_setting; + CAM_DBG(CAM_SENSOR,"Enter"); + + flag_chipv = gc5035_chipversion_buffer[CHIPV_FLAG_OFFSET]; + CAM_DBG(CAM_SENSOR,"gc5035 otp chipv flag_chipv: 0x%x", flag_chipv); + if (VALID_FLAG != (flag_chipv & 0x03)) { + CAM_ERR(CAM_SENSOR,"gc5035 otp chip regs data is Empty/Invalid!"); + return rc; + } + + for (i = 0; i < 5; i++) { + if (VALID_FLAG == ((gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] >> 3) & 0x01)) { + gc5035_update_reg_setting[reg_setting_size].reg_addr = 0xfe; + gc5035_update_reg_setting[reg_setting_size].reg_data = gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] & 0x07; + gc5035_update_reg_setting[reg_setting_size].delay = gc5035_update_reg_setting[reg_setting_size].data_mask = 0; + reg_setting_size++; + gc5035_update_reg_setting[reg_setting_size].reg_addr = gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 1]; + gc5035_update_reg_setting[reg_setting_size].reg_data = gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 2]; + gc5035_update_reg_setting[reg_setting_size].delay = gc5035_update_reg_setting[reg_setting_size].data_mask = 0; + reg_setting_size++; + + CAM_DBG(CAM_SENSOR,"gc5035 otp chipv : 0xfe=0x%x, addr[%d]=0x%x, value[%d]=0x%x", gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] & 0x07,i*2, + gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 1],i*2,gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 2]); + } + if (VALID_FLAG == ((gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] >> 7) & 0x01)) { + gc5035_update_reg_setting[reg_setting_size].reg_addr = 0xfe; + gc5035_update_reg_setting[reg_setting_size].reg_data = (gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] & 0x70) >> 4; + gc5035_update_reg_setting[reg_setting_size].delay = gc5035_update_reg_setting[reg_setting_size].data_mask = 0; + reg_setting_size++; + gc5035_update_reg_setting[reg_setting_size].reg_addr = gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 3]; + gc5035_update_reg_setting[reg_setting_size].reg_data = gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 4]; + gc5035_update_reg_setting[reg_setting_size].delay = gc5035_update_reg_setting[reg_setting_size].data_mask = 0; + reg_setting_size++; + + CAM_DBG(CAM_SENSOR,"gc5035 otp chipv : 0xfe=0x%x, addr[%d]=0x%x, value[%d]=0x%x", (gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i] & 0x70) >> 4,i*2+1, + gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 3],i*2+1,gc5035_chipversion_buffer[CHIPV_OFFSET + 5 * i + 4]); + } + } + sensor_setting.reg_setting = gc5035_update_reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = reg_setting_size; + sensor_setting.delay = 0; + + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "gc5035SpcWrite_setting Failed to write sensor setting"); + return rc; + } + rc = 0; + CAM_DBG(CAM_SENSOR,"Exit"); + return rc; + +} +/******************** GC5035_OTP_EDIT_END*******************/ + +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; + } + } + } + /******************** GC5035_OTP_EDIT_END*******************/ + + if (slave_info->sensor_id == 0x5035 && s_ctrl->sensordata->id_info.sensor_id == 1) { + s_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_FAST_MODE; + sensor_gc5035_get_dpc_data(s_ctrl); + s_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_FAST_PLUS_MODE; + } + /******************** GC5035_OTP_EDIT_END*******************/ + + 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; + } + /******************** GC5035_OTP_EDIT_END*******************/ + if (s_ctrl->sensordata->slave_info.sensor_id == 0x5035 + && opcode == CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG + && s_ctrl->sensordata->id_info.sensor_id == 1) { + sensor_gc5035_write_dpc_data(s_ctrl); + sensor_gc5035_update_reg(s_ctrl); + } + /******************** GC5035_OTP_EDIT_END*******************/ + + } + } + } 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 100755 index 000000000000..b7a5923a6a70 --- /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 000000000000..c908e7404882 --- /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 100755 index 000000000000..b1963e15eb59 --- /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 100755 index 000000000000..2c25ee0aa6f0 --- /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 100755 index 000000000000..99862da046ff --- /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 100755 index 000000000000..5b11171fa087 --- /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 100755 index 000000000000..a5e780a2e119 --- /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 100755 index 000000000000..def8be55bc8b --- /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 100755 index 000000000000..108c47923eb7 --- /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 100755 index 000000000000..f70709997e69 --- /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 100755 index 000000000000..a9fd0881aabf --- /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 100755 index 000000000000..cf6987b09eac --- /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 100755 index 000000000000..73d7ea9456ba --- /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 100755 index 000000000000..d822b2a733cf --- /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 000000000000..b9368fbfa9ba --- /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 100755 index 000000000000..0d82579e7999 --- /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 100755 index 000000000000..c923efe61dc5 --- /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 100755 index 000000000000..b674b48ceb2d --- /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 100755 index 000000000000..090d01dcd5d5 --- /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 100755 index 000000000000..4a4a0d312f9d --- /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 100755 index 000000000000..40efdf4dd794 --- /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 100755 index 000000000000..33b14f17ceb7 --- /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 100755 index 000000000000..3d99bc15eb18 --- /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 100755 index 000000000000..a8612fdcd7c5 --- /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 100755 index 000000000000..f971f7e25dc5 --- /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 100755 index 000000000000..e114c33c655a --- /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 100755 index 000000000000..e17c2f50bb95 --- /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 100755 index 000000000000..dbcb31d7bf0e --- /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 100755 index 000000000000..e202bae5b761 --- /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 100755 index 000000000000..b0f93ba045e0 --- /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 100755 index 000000000000..ab06952b86a8 --- /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 000000000000..593e2a724850 --- /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 000000000000..3b567c16227f --- /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 100755 index 000000000000..d35320e7e487 --- /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 100755 index 000000000000..66aaeaa45d55 --- /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 100755 index 000000000000..75a47ca136a4 --- /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 100755 index 000000000000..21a192357b11 --- /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 100755 index 000000000000..6c564fd8337f --- /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 000000000000..cc82bd67cd67 --- /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 100755 index 000000000000..9b45091b4b85 --- /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 100755 index 000000000000..838997590771 --- /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 100755 index 000000000000..bab1145bc7a7 --- /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 100755 index 000000000000..93dffc4bac8d --- /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 100755 index 000000000000..e7971dac1051 --- /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 100755 index 000000000000..b85ab068f9e8 --- /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 100755 index 000000000000..b36891f4a0dc --- /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 000000000000..6e29b35ace53 --- /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 100755 index 000000000000..126be4555f69 --- /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 100755 index 000000000000..4b5419d2f21d --- /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 100755 index 000000000000..e4778cfc9cc2 --- /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 100755 index 000000000000..34c1b3bd2bfe --- /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 100755 index 000000000000..407124644bcc --- /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 100755 index 000000000000..497093902ba3 --- /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 100755 index 000000000000..fd0ed2a2cfdb --- /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 100755 index 000000000000..e3bd9449f7ef --- /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 100755 index 000000000000..812212f3170b --- /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 100755 index 000000000000..5bab420a7b02 --- /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 100755 index 000000000000..cc86f2706c63 --- /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 100755 index 000000000000..d1ab63fd4294 --- /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 100755 index 000000000000..7da5493466b0 --- /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 100755 index 000000000000..b2829628ff13 --- /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 100755 index 000000000000..987146bb6ddb --- /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 100755 index 000000000000..1ef288bd4182 --- /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 100755 index 000000000000..c76a073ecccd --- /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 100755 index 000000000000..dbbf3c847dbb --- /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 100755 index 000000000000..690d4ec79f41 --- /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 100755 index 000000000000..dbbf3c847dbb --- /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 100755 index 000000000000..049024839701 --- /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 100755 index 000000000000..bd034f0d3263 --- /dev/null +++ b/techpack/display/msm/Makefile @@ -0,0 +1,151 @@ +# 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 \ + +#ifeq ($(CONFIG_PXLW_IRIS),y) +msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/iris/dsi_iris5_ioctl.o \ + dsi/iris/dsi_iris5_lightup.o \ + dsi/iris/dsi_iris5_lightup_ocp.o \ + dsi/iris/dsi_iris5_lp.o \ + dsi/iris/dsi_iris5_lut.o \ + dsi/iris/dsi_iris5_pq.o \ + dsi/iris/dsi_iris5_mode_switch.o \ + dsi/iris/dsi_iris5_cmds.o \ + dsi/iris/dsi_iris5_i3c.o \ + dsi/iris/dsi_iris5_i2c.o \ + dsi/iris/dsi_iris5_loop_back.o \ + dsi/iris/dsi_iris5_gpio.o \ + dsi/iris/dsi_iris5_frc.o \ + dsi/iris/dsi_iris5_timing_switch.o \ + dsi/iris/dsi_iris5_dbg.o \ + dsi/iris/msm_iris5_extended.o \ + dsi/iris/sde_iris5_extended.o \ + dsi/iris/dsi_iris5_extended.o +$(warning "Defined CONFIG_PXLW_IRIS and PXLW_IRIS_DUAL in makefile") +ccflags-y += -DCONFIG_PXLW_IRIS +ccflags-y += -DPXLW_IRIS_DUAL +#endif + +#ifeq ($(CONFIG_PXLW_SOFT_IRIS), y) +#msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/iris/dsi_irissoft_ioctl.o +#ccflags-y += -DCONFIG_PXLW_SOFT_IRIS +#$(warning "Defined CONFIG_PXLW_SOFT_IRIS in makefile") +#endif + +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 100755 index 000000000000..90c3ad16dba6 --- /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 100755 index 000000000000..882551e0fefc --- /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 100755 index 000000000000..b9ae7386bee2 --- /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 100755 index 000000000000..cd0d9714b922 --- /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 100755 index 000000000000..f67302bbc90d --- /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 100755 index 000000000000..0b1f00408e43 --- /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 100755 index 000000000000..97d78a120bc4 --- /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 100755 index 000000000000..a4f3c456b458 --- /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 100755 index 000000000000..c84ec44e6775 --- /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 100755 index 000000000000..a2e20e26fe30 --- /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 100755 index 000000000000..0459adceb1fa --- /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 100755 index 000000000000..aa239be382b8 --- /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 100755 index 000000000000..4823fe2e2850 --- /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 100755 index 000000000000..ebfeb1d67423 --- /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 100755 index 000000000000..976e0ebb8faf --- /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 100755 index 000000000000..07f606e8a70b --- /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 100755 index 000000000000..f11212b63eae --- /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 100755 index 000000000000..0ed305cb906e --- /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 100755 index 000000000000..fcbec753ccfc --- /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 100755 index 000000000000..3c96350ccb3e --- /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 100755 index 000000000000..86806fbdf773 --- /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 100755 index 000000000000..20a09cf9bf5f --- /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 100755 index 000000000000..db3456d973e3 --- /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 100755 index 000000000000..7fbd01449c2f --- /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 100755 index 000000000000..9779331bd295 --- /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 100755 index 000000000000..508e1034feb4 --- /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 100755 index 000000000000..b31103a6cde3 --- /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 100755 index 000000000000..212b61524b22 --- /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 100755 index 000000000000..40a2401b1c4c --- /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 100755 index 000000000000..0970dff71ed0 --- /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 100755 index 000000000000..e14488f43fa0 --- /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 100755 index 000000000000..a5e5f5d93e90 --- /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 100755 index 000000000000..df6a8d3ce8c4 --- /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 100755 index 000000000000..44cfb710af49 --- /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 100755 index 000000000000..899ac4c5960c --- /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 100755 index 000000000000..f26c72964e5a --- /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 100755 index 000000000000..ed047e9ef86d --- /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 100755 index 000000000000..fcd352d19b7b --- /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 100755 index 000000000000..ec2df96605a9 --- /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 100755 index 000000000000..f4133ce4b93f --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl.c @@ -0,0 +1,3912 @@ +// 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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, "%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); + } +} + +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); + + 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); + + 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) { + *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) { +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if ((dsi_ctrl->cmd_len + cmd_len + 4) <= SZ_256K) + return rc; + DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer, size is greater than 256K\n"); + } +#endif + 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); + /* 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 defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + msm_gem_sync(dsi_ctrl->tx_cmd_buf); +#endif + + 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); + +#if defined(CONFIG_PXLW_IRIS) + if (!iris_is_chip_supported()) + msm_gem_sync(dsi_ctrl->tx_cmd_buf); +#else + msm_gem_sync(dsi_ctrl->tx_cmd_buf); +#endif + + 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"); + 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); + 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(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); + 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_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); + + 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); + + 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); + + 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 100755 index 000000000000..d1ad3862d3dc --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl.h @@ -0,0 +1,871 @@ +/* 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); +#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 100755 index 000000000000..9411e98c0fb6 --- /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 100755 index 000000000000..1fa0b51207aa --- /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 100755 index 000000000000..3af3225d77bd --- /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 100755 index 000000000000..0c6d3404a268 --- /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 100755 index 000000000000..6a85cd792250 --- /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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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 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 */ +#if defined(CONFIG_PXLW_IRIS) + /* set DMA FIFO read watermark to 15/16 full */ + if (iris_is_chip_supported()) + reg = 0x33; +#endif + + 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 100755 index 000000000000..43a11530555a --- /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 100755 index 000000000000..270b5ea2aa44 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -0,0 +1,806 @@ +/* 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, "[%d]: " fmt, __LINE__, \ + ##__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_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_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_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_SET_AOD_OFF_NEW, + DSI_CMD_SET_AOD_OFF_SAMSUNG, + DSI_CMD_AOD_OFF_HBM_ON_SETTING, + DSI_CMD_REAL_AOD_OFF_HBM_ON_SETTING, + DSI_CMD_HBM_OFF_AOD_ON_SETTING, + + 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_NATIVE_DISPLAY_SRGB_COLOR_ON, + DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_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_DCI_P3_ON, + DSI_CMD_SET_DCI_P3_OFF, + 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_NIGHT_ON, + DSI_CMD_SET_NIGHT_OFF, + + DSI_CMD_SET_ACL_MODE, + DSI_CMD_LOADING_EFFECT_ON, + DSI_CMD_LOADING_EFFECT_OFF, + DSI_CMD_SET_MCA_SETTING_MODE_1, + DSI_CMD_SET_MCA_SETTING_MODE_0, + DSI_CMD_SET_GAMMA_FLASH_PRE_READ_1, + DSI_CMD_SET_GAMMA_FLASH_PRE_READ_2, + DSI_CMD_SET_GAMMA_OTP_READ_C8_SMRPS, + DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS, + DSI_CMD_SET_GAMMA_OTP_READ_B3_SMRPS, + DSI_CMD_SET_GAMMA_CHANGE_WRITE, + + DSI_CMD_SET_PANEL_ID, + DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ED_ON, + DSI_CMD_SET_113MHZ_OSC_ON, + DSI_CMD_POST_ON_BACKLIGHT, + DSI_CMD_SET_SEED_COMMAND, + DSI_CMD_SET_PANEL_COMMAND, + DSI_CMD_SET_REGISTER_READ, + DSI_CMD_SET_LEVEL2_KEY_ENABLE, + DSI_CMD_SET_LEVEL2_KEY_DISABLE, +#if defined(CONFIG_PXLW_IRIS) + DSI_CMD_SET_ABYP, +#endif + 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. + * @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 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 100755 index 000000000000..ea82f2cbda84 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display.c @@ -0,0 +1,12077 @@ +// 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#include "iris/dsi_iris5_lightup.h" +#include "iris/dsi_iris5_loop_back.h" +#include <video/mipi_display.h> +#elif defined(CONFIG_PXLW_SOFT_IRIS) +#include "iris/dsi_iris5_api.h" +#endif +#include <linux/oem/boot_mode.h> +#define to_dsi_display(x) container_of(x, struct dsi_display, host) +#define INT_BASE_10 10 + +#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 + +static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; +static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; +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}; +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; +} + +int dsi_display_back_ToolsType_ANA6706(u8 *buff) +{ + int i; + int WaferNumber; + eTool typeTool; + char szLotID[6] = {0}; + unsigned char chipID1[4] = {0}; + + for(i = 0; i < 4; i++) + chipID1[i] = buff[i]; + + // [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 WaferNo: %d, Tool: Tool-B (%d)\n", szLotID, WaferNumber, typeTool); + else if (typeTool == ToolA) + DSI_ERR("Result: 6706 LotID: %s WaferNo: %d, Tool: Tool-A (%d)\n", szLotID, WaferNumber, typeTool); + else if (typeTool == ToolA_HVS30) + DSI_ERR("Result: 6706 LotID: %s WaferNo: %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; + break; + } + } + + return typeTool; +} + +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; + + if (dsi_display == NULL || dsi_display->panel == NULL) + return -EINVAL; + + panel = dsi_display->panel; + + 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 != 0 && bl_lvl != INVALID_BL_VALUE && panel->bl_config.bl_level == 0) { + if (strcmp(dsi_display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + if (panel->naive_display_p3_mode) { + mdelay(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) { + mdelay(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) { + mdelay(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"); + } + 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 if (strcmp(dsi_display->panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 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_RGB_OFF); + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_RGB_OFF 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"); + } + } + } + + if (bl_lvl != INVALID_BL_VALUE) + panel->bl_config.bl_level = bl_lvl; + else + bl_lvl = panel->bl_config.bl_level; + /* 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"); + + 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 ((0 == panel->panel_serial_number) && + (strcmp(dsi_display->panel->name, "samsung sofef00_m video mode dsi panel") != 0)) { + dsi_display_get_serial_number(connector); + } + + if ((gamma_read_flag < 2) && ((strcmp(dsi_display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) + || (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0))) { + if (gamma_read_flag < 1) { + gamma_read_flag++; + } + else { + schedule_delayed_work(&dsi_display->panel->gamma_read_work, 0); + gamma_read_flag++; + } + } + + 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; +} + +#if defined(CONFIG_PXLW_IRIS) +int iris_display_cmd_engine_enable(struct dsi_display *display) +{ + return dsi_display_cmd_engine_enable(display); +} +#endif + +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; +} +#if defined(CONFIG_PXLW_IRIS) +int iris_display_cmd_engine_disable(struct dsi_display *display) +{ + return dsi_display_cmd_engine_disable(display); +} +#endif + +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_err_flag_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) || (!display->panel->is_err_flag_irq_enabled) || (!display->panel->panel_initialized)) + return IRQ_HANDLED; + + DSI_ERR("%s\n", __func__); + + if (!display->panel->err_flag_status) { + display->panel->err_flag_status = true; + cancel_delayed_work_sync(sde_esk_check_delayed_work); + schedule_delayed_work(sde_esk_check_delayed_work, 0); + DSI_ERR("schedule sde_esd_check_delayed_work\n"); + } + + return IRQ_HANDLED; +} + +void dsi_display_change_err_flag_irq_status(struct dsi_display *display, + bool enable) +{ + if (!display) { + DSI_ERR("Invalid params\n"); + return; + } + + if (!gpio_is_valid(display->panel->err_flag_gpio)) + return; + + /* Handle unbalanced irq enable/disbale calls */ + if (enable && !display->panel->is_err_flag_irq_enabled) { + enable_irq(gpio_to_irq(display->panel->err_flag_gpio)); + display->panel->is_err_flag_irq_enabled = true; + DSI_ERR("enable err flag irq\n"); + } else if (!enable && display->panel->is_err_flag_irq_enabled) { + disable_irq(gpio_to_irq(display->panel->err_flag_gpio)); + display->panel->is_err_flag_irq_enabled = false; + DSI_ERR("disable err flag irq\n"); + } +} +EXPORT_SYMBOL(dsi_display_change_err_flag_irq_status); + +static void dsi_display_register_err_flag_irq(struct dsi_display *display) +{ + int rc = 0; + struct platform_device *pdev; + struct device *dev; + unsigned int err_flag_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->panel->err_flag_gpio)) { + DSI_ERR("Failed to get err-flag-gpio\n"); + rc = -EINVAL; + return; + } + + err_flag_irq = gpio_to_irq(display->panel->err_flag_gpio); + + /* Avoid deferred spurious irqs with disable_irq() */ + irq_set_status_flags(err_flag_irq, IRQ_DISABLE_UNLAZY); + + rc = devm_request_irq(dev, err_flag_irq, dsi_display_panel_err_flag_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "ERR_FLAG_GPIO", display); + if (rc) { + DSI_ERR("Err flag request_irq failed for ESD rc:%d\n", rc); + irq_clear_status_flags(err_flag_irq, IRQ_DISABLE_UNLAZY); + return; + } + + disable_irq(err_flag_irq); + display->panel->is_err_flag_irq_enabled = false; +} + +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; + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + display->tx_cmd_buf = msm_gem_new(display->drm_dev, + SZ_256K, + MSM_BO_UNCACHED); + } else +#endif + 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; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + display->cmd_buffer_size = SZ_256K; +#endif + + 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; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + display_ctrl->ctrl->cmd_buffer_size = SZ_256K; +#endif + 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; + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + rc = iris_read_status(ctrl, panel); + if (rc == 2) + rc = dsi_display_read_status(ctrl, panel); + } else +#endif + 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_display_status_reg_read(struct dsi_display *display) +{ + int rc = 0, i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + struct dsi_display_mode *mode; + struct dsi_panel *panel = NULL; + + int count = 0; + #if defined(CONFIG_PXLW_IRIS) + struct dsi_cmd_desc *cmds; + unsigned char *payload; + #endif + unsigned char register1[10] = {0}; + unsigned char register2[10] = {0}; + unsigned char register3[10] = {0}; + unsigned char register4[10] = {0}; + + 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; + } + + if (!display->panel || !display->panel->cur_mode) { + rc = -EINVAL; + goto exit; + } + + if ((strcmp(display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) || + (strcmp(display->panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) || + (strcmp(display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) || + (strcmp(display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(display->panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") == 0)) { + + mode = display->panel->cur_mode; + panel = display->panel; + + 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 { + 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 commands\n"); + goto exit; + } + } + + if (strcmp(panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + dsi_display_register_read(display, 0x0E, register1, 1); + dsi_display_register_read(display, 0xEA, register2, 1); + + if((register1[0] !=0x80) && (register2[0] != 0x80)) { + rc = -1; + } else { + rc = 1; + } + } else if (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) { + dsi_display_register_read(display, 0x0A, register1, 1); + dsi_display_register_read(display, 0xB6, register2, 1); + + if ((register1[0] != 0x9c) || (register2[0] != 0x0a)) { + if (register1[0] != 0x9c) + esd_black_count++; + if (register2[0] != 0x0a) + 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 if (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) { + rc = iris_get_status(); + if (rc <= 0) { + DSI_ERR("Iris ESD snow screen error\n"); + goto exit; + } + + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_REGISTER_READ].cmds; + payload = (u8 *)cmds[0].msg.tx_buf; + payload[0] = 0xE9; + rc = iris_panel_ctrl_read_reg(m_ctrl, panel, register1, 4, cmds); + if (rc <= 0) { + DSI_ERR("iris_panel_ctrl_read_reg 1 failed, rc=%d\n", rc); + goto exit; + } + + payload[0] = 0x0A; + rc = iris_panel_ctrl_read_reg(m_ctrl, panel, register2, 1, cmds); + if (rc <= 0) { + DSI_ERR("iris_panel_ctrl_read_reg 2 failed, rc=%d\n", rc); + goto exit; + } + } else { +#else + { +#endif + rc = dsi_display_register_read(display, 0xE9, register1, 4); + if (rc <= 0) + goto exit; + + rc = dsi_display_register_read(display, 0x0A, register2, 1); + if (rc <= 0) + goto exit; + } + + DSI_ERR("0xE9 = %02x, %02x, %02x, %02x, 0x0A = %02x\n", register1[0], register1[1], register1[2], register1[3], register2[0]); + if (((register1[3] != 0x00) && (register1[3] != 0x02) && (register1[3] != 0x06)) || (register2[0] != 0x9C)) { + if ((register1[3] == 0x10) || (register1[3] == 0x30) || (register1[3] == 0x32) + || (register1[3] == 0x38) || (register1[3] == 0x18) || (register1[3] == 0x08)) + DSI_ERR("ESD color dot error\n"); + if ((register1[3] == 0x31) || (register1[3] == 0x33)) + DSI_ERR("ESD snow screen error\n"); + if (register2[0] != 0x9C) + DSI_ERR("ESD black screen error\n"); + rc = -1; + } else { + rc = 1; + } + } else if (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) { + rc = dsi_display_register_read(display, 0x0A, register1, 1); + if (rc <= 0) + goto exit; + + rc = dsi_display_register_read(display, 0xEE, register2, 1); + if (rc <= 0) + goto exit; + + rc = dsi_display_register_read(display, 0xE5, register3, 1); + if (rc <= 0) + 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; + } + } + rc = dsi_display_register_read(display, 0xED, register4, 1); + if (rc <= 0) + goto exit; + + if ((register1[0] != 0x9c) || ((register2[0] != 0x00) && (register2[0] != 0x80)) + || ((register3[0] != 0x13) && (register3[0] != 0x12)) || (register4[0] != 0x97)) { + DSI_ERR("0x0A = %02x, 0xEE = %02x, 0xE5 = %02x, 0xED = %02x\n", register1[0], register2[0], register3[0], register4[0]); + if (register1[0] != 0x9c) + esd_black_count++; + if ((register2[0] != 0x00) || (register3[0] != 0x13) || (register4[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 if (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") == 0) { + rc = dsi_display_register_read(display, 0x0A, register1, 1); + if (rc <= 0) + goto exit; + + rc = dsi_display_register_read(display, 0xB6, register2, 1); + if (rc <= 0) + goto exit; + + rc = dsi_display_register_read(display, 0xA2, register3, 5); + if (rc <= 0) + goto exit; + + DSI_ERR("0x0A = %02x, 0xB6 = %02x, 0xA2 = %02x, %02x, %02x, %02x, %02x\n", register1[0], register2[0], + register3[0], register3[1], register3[2], register3[3], register3[4]); + + if ((register1[0] != 0x9c) || (register2[0] != 0x0a) || (register3[0] != 0x11) || (register3[1] != 0x00) + || (register3[2] != 0x00) || (register3[3] != 0x89) || (register3[4] != 0x30)) { + if ((register1[0] != 0x9c) || (register3[0] != 0x11) || (register3[1] != 0x00) + || (register3[2] != 0x00) || (register3[3] != 0x89) || (register3[4] != 0x30)) + esd_black_count++; + if (register2[0] != 0x0a) + esd_greenish_count++; + DSI_ERR("black_count=%d, greenish_count=%d, total=%d\n", + esd_black_count, esd_greenish_count, esd_black_count + esd_greenish_count); + rc = -1; + } else { + rc = 1; + } + } + + 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); + } 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; + 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); + + 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 ana6706 dsc cmd mode 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); + + 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; + } + + 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; +} +#if defined(CONFIG_PXLW_IRIS) +int iris_dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, + bool *state) +{ + return dsi_display_ctrl_get_host_init_state(dsi_display, state); +} +#endif + +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); + } + } + 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 start */ + 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 + /* send screen off cmd for tp end */ + break; + default: + return 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; + } +#if defined(CONFIG_PXLW_IRIS) + iris_dsi_display_debugfs_init(display, dir, dump_file); +#endif + + 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; + } + +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; + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (msg->rx_buf && msg->rx_len) + cmd_flags |= DSI_CTRL_CMD_READ; + } +#endif + rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, + &cmd_flags); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (rc > 0) + rc = 0; + } +#endif + 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 clk *bb_clk2; + 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; + } + if (dsi_display_check_prefix("pw_bb_clk2", clk_name)) { + bb_clk2 = dsi_clk; + if(get_oem_project() != 19811){ + clk_prepare_enable(bb_clk2); + clk_disable_unprepare(bb_clk2); //disable the clk + DSI_ERR("%s %d\n",__func__,get_oem_project()); + } + 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; + } + +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + iris_dsi_display_res_init(display); +#endif + + 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; + } + + if ((strcmp(display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) + || (strcmp(display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0)) { + 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); + + 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); + 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); + 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); + 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) + 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); + + /* 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; + } +#if defined(CONFIG_PXLW_IRIS) + iris_control_pwr_regulator(true); +#endif + /* 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); + + 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) + 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); + dsi_display_register_err_flag_irq(display); +#if defined(CONFIG_PXLW_IRIS) + /* register osd irq handler */ + iris_register_osd_irq(display); +#endif + + 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; + display->name = "dsi_firmware_display"; + } else { + DSI_INFO("no firmware available, fallback to device node\n"); + } + + if (dsi_display_init(display)) + return; + + DSI_DEBUG("success\n"); +} + +#if defined(CONFIG_PXLW_IRIS) +static int dsi_display_parse_boot_display_selection_iris(struct platform_device *pdev) +{ + // Add secondary display. + int i; + struct device_node *node = NULL, *mdp_node = NULL; + const char *disp_name = NULL; + static const char * const disp_name_type[] = { + "pxlw,dsi-display-primary-active", + "pxlw,dsi-display-secondary-active"}; + + node = pdev->dev.of_node; + mdp_node = of_parse_phandle(node, "qcom,mdp", 0); + if (!mdp_node) { + DSI_ERR("mdp_node not found\n"); + return -ENODEV; + } + + for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { + DSI_INFO("IRIS_LOG I UEFI display[%d] name: %s\n", i, boot_displays[i].name); + of_property_read_string(mdp_node, disp_name_type[i], &disp_name); + if (disp_name) { + if (i == 0) { + if (strstr(boot_displays[i].name, disp_name) == NULL) + break; + disp_name = NULL; + } else { + DSI_INFO("IRIS_LOG I actual display[%d] name: %s\n", i, disp_name); + strlcpy(boot_displays[i].name, disp_name, + MAX_CMDLINE_PARAM_LEN); + boot_displays[i].boot_disp_en = true; + disp_name = NULL; + } + } else { + break; + } + } + return 0; +} +#endif + +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; + +#if defined(CONFIG_PXLW_IRIS) + if (index == DSI_PRIMARY) + dsi_display_parse_boot_display_selection_iris(pdev); +#endif + + 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)) { + firm_req = !request_firmware_nowait( + THIS_MODULE, 1, "dsi_prop", + &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); + +#if defined(CONFIG_PXLW_IRIS) + iris_deinit(display); +#endif + /* 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) + 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_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(cur_mode->timing.refresh_rate, + adj_mode->timing.refresh_rate, + cur_mode->timing.h_front_porch, + adj_mode->timing.h_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(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); +#if defined(CONFIG_PXLW_IRIS) + iris_prepare(display); +#endif + 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; + + SDE_ATRACE_BEGIN("dsi_display_pre_kickoff"); + /* 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; + SDE_ATRACE_BEGIN("dsi_ctrl_wait_for_cmd_mode_mdp_idle"); + ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl); + SDE_ATRACE_END("dsi_ctrl_wait_for_cmd_mode_mdp_idle"); + if (ret) + goto wait_failure; + } + + /* + * Don't check the return value so as not to impact DRM commit + * when error occurs. + */ + SDE_ATRACE_BEGIN("dsi_display_force_update_dsi_clk"); + (void)dsi_display_force_update_dsi_clk(display); + SDE_ATRACE_END("dsi_display_force_update_dsi_clk"); +wait_failure: + /* release panel_lock */ + dsi_panel_release_panel_lock(display->panel); + mutex_unlock(&display->display_lock); + } + + SDE_ATRACE_END("dsi_display_pre_kickoff"); + 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; + SDE_ATRACE_BEGIN("dsi_display_enable"); + + 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); +#if defined(CONFIG_PXLW_IRIS) + iris_send_cont_splash(display); +#endif + + 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) { + SDE_ATRACE_BEGIN("dsi_panel_post_switch"); + rc = dsi_panel_post_switch(display->panel); + SDE_ATRACE_END("dsi_panel_post_switch"); + 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)){ + SDE_ATRACE_BEGIN("dsi_panel_enable"); + rc = dsi_panel_enable(display->panel); + SDE_ATRACE_END("dsi_panel_enable"); + 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->priv_info->dsc.pic_width *= display->ctrl_count; + SDE_ATRACE_BEGIN("dsi_panel_update_pps"); + rc = dsi_panel_update_pps(display->panel); + SDE_ATRACE_END("dsi_panel_update_pps"); + 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) { + SDE_ATRACE_BEGIN("dsi_panel_switch"); + rc = dsi_panel_switch(display->panel); + SDE_ATRACE_END("dsi_panel_switch"); + 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__); + SDE_ATRACE_BEGIN("dsi_display_cmd_engine_enable"); + rc = dsi_display_cmd_engine_enable(display); + SDE_ATRACE_END("dsi_display_cmd_engine_enable"); + 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; + } + SDE_ATRACE_END("dsi_display_enable"); + + goto error; + +error_disable_panel: + (void)dsi_panel_disable(display->panel); +error: + mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + + SDE_ATRACE_END("dsi_display_enable"); + 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_register_read(struct dsi_display *dsi_display, unsigned char registers, char *buf, size_t count) +{ + int rc = 0; + int flags = 0; + int cmd_count = 0; + int retry_times = 0; + unsigned char *payload; + struct dsi_cmd_desc *cmds; + struct dsi_display_mode *mode; + struct dsi_display_ctrl *m_ctrl; + + if (!dsi_display || !dsi_display->panel->cur_mode || !registers || !buf || !count) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mode = dsi_display->panel->cur_mode; + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + cmd_count = mode->priv_info->cmd_sets[DSI_CMD_SET_REGISTER_READ].count; + + if (!m_ctrl || !m_ctrl->ctrl->vaddr || !cmd_count) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_REGISTER_READ].cmds; + payload = (u8 *)cmds[0].msg.tx_buf; + payload[0] = registers; + + 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 = buf; + cmds->msg.rx_len = count; + 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); + + 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; + 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; + + DSI_ERR("start\n", __func__); + + if (!panel || !panel->cur_mode) + 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); + +/* 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; + } + + rc = dsi_display_register_read(dsi_display, 0xFB, fb_temp, 13); + if (rc <= 0) { + DSI_ERR("Failed to read 0xFB registers\n"); + goto error; + } + + 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_temp[12]; + } + else if (i < 315) { + gamma_para[0][i+26] = fb_temp[12]; + } + else if (i < 360) { + gamma_para[0][i+43] = fb_temp[12]; + } + + gamma_para_60hz[i] = fb_temp[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; + } + + rc = dsi_display_register_read(dsi_display, 0xC8, c8_temp, 135); + if (rc <= 0) { + DSI_ERR("Failed to read 0xC8 registers\n"); + goto error; + } + memcpy(&gamma_para[1][18], c8_temp, 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; + } + + rc = dsi_display_register_read(dsi_display, 0xC9, c9_temp, 180); + if (rc <= 0) { + DSI_ERR("Failed to read 0xC8 registers\n"); + goto error; + } + memcpy(&gamma_para[1][161], c9_temp, 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; + } + + rc = dsi_display_register_read(dsi_display, 0xB3, b3_temp, 47); + if (rc <= 0) { + DSI_ERR("Failed to read 0xB3 registers\n"); + goto error; + } + memcpy(&gamma_para[1][358], &b3_temp[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; +} + +extern bool HBM_flag; +int dsi_display_get_dimming_gamma_para(struct dsi_display *dsi_display, struct dsi_panel *panel) +{ + int rc = 0; + int count = 0; + unsigned char payload = 0; + struct mipi_dsi_device *dsi; + struct dsi_display_mode *mode; + + mode = panel->cur_mode; + dsi = &panel->mipi_device; + if (!dsi_display || !panel || !mode || !dsi) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return rc; + } + + dsi_panel_acquire_panel_lock(panel); + + 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 { + 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 commands\n"); + goto error; + } + } + + payload = 0xA4; + rc = mipi_dsi_dcs_write(dsi, 0xB0, &payload, sizeof(payload)); + if (rc < 0) { + DSI_ERR("Failed to write mipi dsi dcs cmd\n"); + goto error; + } + + rc = dsi_display_register_read(dsi_display, 0xC9, dimming_gamma_60hz, 5); + if (rc <= 0) { + DSI_ERR("Failed to read 0xC9 registers\n"); + 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 { + 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 commands\n"); + goto error; + } + } + + 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 { + 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 commands\n"); + goto error; + } + } + + payload = 0xA7; + rc = mipi_dsi_dcs_write(dsi, 0xB0, &payload, sizeof(payload)); + if (rc < 0) { + DSI_ERR("Failed to write mipi dsi dcs cmd\n"); + goto error; + } + + rc = dsi_display_register_read(dsi_display, 0xC7, dimming_gamma_120hz, 5); + if (rc <= 0) { + DSI_ERR("Failed to read 0xC7 registers\n"); + 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 { + 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 commands\n"); + goto error; + } + } + + 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 { + 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 commands\n"); + goto error; + } + } + + payload = 0x17; + rc = mipi_dsi_dcs_write(dsi, 0xB0, &payload, sizeof(payload)); + if (rc < 0) { + DSI_ERR("Failed to write mipi dsi dcs cmd\n"); + goto error; + } + + rc = dsi_display_register_read(dsi_display, 0xC9, &dimming_gamma_60hz[15], 5); + if (rc <= 0) { + DSI_ERR("Failed to read 0xC9 registers\n"); + 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 { + 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 commands\n"); + goto error; + } + } + + dsi_panel_update_gamma_change_write(); + + rc = dsi_panel_dimming_gamma_write(panel); + if (rc < 0) + DSI_ERR("Failed to write dimming gamma, rc=%d\n", rc); + HBM_flag = false; + +error: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + return rc; +} + +int dsi_display_gamma_read(struct dsi_display *dsi_display) +{ + int rc = 0; + struct dsi_panel *panel = NULL; + + DSI_ERR("start\n"); + 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; + } + + if (strcmp(dsi_display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + rc = dsi_display_get_gamma_para(dsi_display, panel); + if (rc) + DSI_ERR("Failed to dsi_display_get_gamma_para\n"); + } + else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + rc = dsi_display_get_dimming_gamma_para(dsi_display, panel); + if (rc) + DSI_ERR("Failed to dsi_display_get_dimming_gamma_para\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); + DSI_ERR("end\n"); + return rc; +} + +void dsi_display_gamma_read_work(struct work_struct *work) +{ + struct dsi_display *dsi_display; + + dsi_display = get_main_display(); + + if (strcmp(dsi_display->panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + 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(); + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + dsi_display_gamma_read(dsi_display); + } +} + +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 count = 0; + unsigned char panel_ic_v = 0; + unsigned char register_d6[10] = {0}; + int ddic_x = 0; + int ddic_y = 0; + unsigned char code_info = 0; + unsigned char stage_info = 0; + unsigned char prodution_info = 0; + + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) + 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 { + 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 commands\n"); + goto error; + } + } + + if(strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + dsi_display_register_read(dsi_display, 0xFA, &panel_ic_v, 1); + panel->panel_ic_v = panel_ic_v & 0x0f; + } + + if ((strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) + || (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") == 0)) { + dsi_display_register_read(dsi_display, 0xD6, register_d6, 10); + + 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("ddic_x = %d, ddic_y = %d\n", panel->ddic_x, panel->ddic_y); + len = 14; + } + + dsi_display_register_read(dsi_display, 0xA1, buf, len); + + dsi_display_register_read(dsi_display, 0xDA, &code_info, 1); + panel->panel_code_info = code_info; + DSI_ERR("Code info is 0x%X\n", panel->panel_code_info); + + dsi_display_register_read(dsi_display, 0xDB, &stage_info, 1); + panel->panel_stage_info = stage_info; + DSI_ERR("Stage info is 0x%X\n", panel->panel_stage_info); + + dsi_display_register_read(dsi_display, 0xDC, &prodution_info, 1); + panel->panel_production_info = prodution_info; + DSI_ERR("Production info is 0x%X\n", panel->panel_production_info); + + 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 { + 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 commands\n"); + goto error; + } + } + +error: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + return rc; +} + +int dsi_display_get_serial_number(struct drm_connector *connector) +{ + struct dsi_display_mode *mode; + struct dsi_panel *panel; + struct dsi_display *dsi_display; + struct dsi_bridge *c_bridge; + int len = 0; + int count = 0; + int rc = -EINVAL; + + char buf[32] = {0}; + 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; + + DSI_DEBUG("start\n", __func__); + + 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); + + if (!dsi_panel_initialized(panel) || !panel->cur_mode) + goto error; + + mode = panel->cur_mode; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_REGISTER_READ].count; + if (count) { + len = panel->panel_msec_low_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) || (panel->panel_sec_index > len) + || (panel->panel_msec_high_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; + } + + 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) + DSI_ERR("Panel Year not corrected.\n"); + 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_msec = 0; + } + panel_msec_int = panel_msec / 10; + panel_msec_rem = panel_msec % 10; + + 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; + + panel->panel_serial_number = (u64)panel_year * 10000000000 + (u64)panel_mon * 100000000 + (u64)panel_day * 1000000 + + (u64)panel_hour * 10000 + (u64)panel_min * 100 + (u64)panel_sec; + + 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("end\n"); + return rc; +} + +int dsi_display_get_serial_number_year(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->panel_msec_rem; +} + +int dsi_display_get_serial_number_at(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->panel_serial_number; +} + +int dsi_display_get_code_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->panel_code_info; +} + +int dsi_display_get_stage_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->panel_production_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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->panel_ic_v; +} + +char* dsi_display_get_ic_reg_buf(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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("end\n"); + + return dsi_display->panel->buf_select; +} + +int dsi_display_get_ToolsType_ANA6706(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + DSI_DEBUG("end\n"); + + 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("start\n"); + + 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; + + ddic_x = dsi_display->panel->ddic_x; + panel_tool = dsi_display->panel->panel_tool; + +/* + ToolB 0 + ToolA 1 + ToolA_HVS30 2 +*/ + + switch (dsi_display->panel->ddic_y) { + case 2: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 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 ana6705 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 56) && (ddic_x < 245)) { + dsi_display->panel->ddic_check_info = 1; + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + if ((panel_tool == 0) && (ddic_x > 54) && (ddic_x < 140)) + dsi_display->panel->ddic_check_info = 1; + else if (((panel_tool == 1) || (panel_tool == 2)) && (ddic_x > 32) && (ddic_x < 154)) + dsi_display->panel->ddic_check_info = 1; + else + dsi_display->panel->ddic_check_info = 0; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 4: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 40) && (ddic_x < 261)) { + dsi_display->panel->ddic_check_info = 1; + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + if ((panel_tool == 0) && (ddic_x > 46) && (ddic_x < 140)) + dsi_display->panel->ddic_check_info = 1; + else if (((panel_tool == 1) || (panel_tool == 2)) && (ddic_x > 24) && (ddic_x < 162)) + dsi_display->panel->ddic_check_info = 1; + else + dsi_display->panel->ddic_check_info = 0; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 5: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 33) && (ddic_x < 268)) { + dsi_display->panel->ddic_check_info = 1; + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + if ((panel_tool == 0) && (ddic_x > 46) && (ddic_x < 140)) + dsi_display->panel->ddic_check_info = 1; + else if (((panel_tool == 1) || (panel_tool == 2)) && (ddic_x > 23) && (ddic_x < 163)) + dsi_display->panel->ddic_check_info = 1; + else + dsi_display->panel->ddic_check_info = 0; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 6: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 41) && (ddic_x < 261)) { + dsi_display->panel->ddic_check_info = 1; + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + if((panel_tool == 0) && (ddic_x > 54) && (ddic_x < 132)) + dsi_display->panel->ddic_check_info = 1; + else if (((panel_tool == 1) || (panel_tool == 2)) && (ddic_x > 30) && (ddic_x < 156)) + dsi_display->panel->ddic_check_info = 1; + else + dsi_display->panel->ddic_check_info = 0; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 7: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 57) && (ddic_x < 245)) { + dsi_display->panel->ddic_check_info = 1; + } else if (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0) { + if(((panel_tool == 1) || (panel_tool == 2)) && (ddic_x > 45) && (ddic_x < 141)) + dsi_display->panel->ddic_check_info = 1; + else + dsi_display->panel->ddic_check_info = 0; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 8: + if ((strcmp(dsi_display->panel->name, "samsung ana6705 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("Result:panel_tool = %d\n", panel_tool); + + if (panel_tool == 10) + dsi_display->panel->ddic_check_info = 0; + + DSI_DEBUG("end\n"); + + return dsi_display->panel->ddic_check_info; +} + +int iris_loop_back_test(struct drm_connector *connector) +{ + int ret = -1; +#if defined(CONFIG_PXLW_IRIS) + struct iris_cfg *pcfg; + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_ERR("%s start\n", __func__); + 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; + + if (dsi_display->panel->panel_initialized == true) { + pcfg = iris_get_cfg(); + mutex_lock(&pcfg->lb_mutex); + ret = iris_loop_back_validate(); + DSI_ERR("iris_loop_back_validate finish, ret = %d", ret); + mutex_unlock(&pcfg->lb_mutex); + } + DSI_ERR("%s end\n", __func__); +#endif + return ret; +} + +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; + + if ((strcmp(dsi_display->panel->name, "samsung dsc cmd mode oneplus dsi panel") != 0) + && (strcmp(dsi_display->panel->name, "BOE dsc cmd mode oneplus dsi panel") != 0) + && (strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") != 0) + && (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") != 0) + && (strcmp(panel->name, "samsung dd305 fhd cmd mode dsc dsi panel") != 0) + && (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") != 0)) { + dsi_display->panel->hbm_brightness = 0; + return 0; + } + + 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_get_mca_setting_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 -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + return dsi_display->panel->mca_setting_mode; +} + +int dsi_display_set_mca_setting_mode(struct drm_connector *connector, int mca_setting_mode) +{ + 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 ana6706 dsc cmd mode panel") != 0) { + dsi_display->panel->mca_setting_mode = 1; + return 0; + } + + mutex_lock(&dsi_display->display_lock); + + panel->mca_setting_mode = mca_setting_mode; + + 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; + } + + mutex_lock(&panel->panel_lock); + rc = dsi_panel_set_mca_setting_mode(panel, mca_setting_mode); + if (rc) + DSI_ERR("Failed to set mca setting mode %d\n", mca_setting_mode); + mutex_unlock(&panel->panel_lock); + + 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_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 dsc cmd mode oneplus dsi panel") != 0) && + (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6706 dsc cmd mode 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 dsc cmd mode oneplus dsi panel") != 0) && + (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6706 dsc cmd mode 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 dsc cmd mode oneplus dsi panel") == 0) + data[0] = WU_SEED_REGISTER; + if ((strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ana6706 dsc cmd mode 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 dsc cmd mode oneplus dsi panel") != 0) && + (strcmp(dsi_display->panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") != 0) && + (strcmp(dsi_display->panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(dsi_display->panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") != 0) && + (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode 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); + } +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) { + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND].cmds; + rc = iris_panel_ctrl_read_reg(m_ctrl, panel, reg_read_value, reg_read_len, cmds); + if (rc <= 0) + DSI_ERR("iris_panel_ctrl_read_reg failed, rc=%d\n", rc); + } else { +#else + { +#endif + 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 dsc cmd mode oneplus dsi panel") != 0) && + (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ana6706 dsc cmd mode 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; +} + +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; +} + +//*mark.yao@PSW.MM.Display.LCD.Stability,2018/4/28,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 100755 index 000000000000..ae4fd8da27a9 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display.h @@ -0,0 +1,751 @@ +/* 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; +#if defined(CONFIG_PXLW_IRIS) + u32 off; + u32 cnt; + u8 cmd_data_type; +#endif + 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); + +/** + * 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 struct delayed_work *sde_esk_check_delayed_work; + +int dsi_display_register_read(struct dsi_display *dsi_display, unsigned char registers, char *buf, size_t count); +int dsi_display_back_ToolsType_ANA6706(u8 *buff); +int dsi_display_get_serial_number(struct drm_connector *connector); + +extern char gamma_para[2][413]; +int dsi_display_gamma_read(struct dsi_display *dsi_display); +void dsi_display_gamma_read_work(struct work_struct *work); +#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 100755 index 000000000000..60f83958c892 --- /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 100755 index 000000000000..b05270a27af1 --- /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 100755 index 000000000000..3093654aa535 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_drm.c @@ -0,0 +1,1064 @@ +// 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_encoder.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; + bool clone_mode = false; + struct drm_encoder *encoder; + + 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; + } + + drm_for_each_encoder(encoder, crtc_state->crtc->dev) { + if (encoder->crtc != crtc_state->crtc) + continue; + + if (sde_encoder_in_clone_mode(encoder)) + clone_mode = true; + } + + /* 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; + /* 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; + } + + /* 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 100755 index 000000000000..ec012c2cb529 --- /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 100755 index 000000000000..cf849a4ae78b --- /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 100755 index 000000000000..37e92e9518bc --- /dev/null +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -0,0 +1,6746 @@ +// 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#include "iris/dsi_iris5_gpio.h" +#endif +#include <linux/pm_wakeup.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_S6E3HC2 0 +#define DSI_PANEL_SAMSUNG_S6E3FC2X01 1 +#define DSI_PANEL_SAMSUNG_SOFEF03F_M 2 +#define DSI_PANEL_SAMSUNG_ANA6705 3 +#define DSI_PANEL_SAMSUNG_ANA6706 4 +#define DSI_PANEL_SAMSUNG_AMB655XL 5 +#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}, + }; + +#if defined(CONFIG_PXLW_IRIS) +static char dsi_dsc_rc_range_max_qp_1_1_pxlw[15] = { + 8, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}; +#endif + +/* + * 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 = 1440; +static struct dsi_panel_cmd_set gamma_cmd_set[2]; + +char dimming_gamma_60hz[30] = {0}; +char dimming_gamma_120hz[15] = {0}; + +char gamma_para[2][413] = { +{ +/* Level2 key Enable */ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0x5A,0x5A, +/* 135 parameter read value (60Hz) */ +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, +/* 180 parameter read value (60Hz) */ +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, +/*0xB0 0x02*/ +0x15,0x01,0x00,0x00,0x00,0x00,0x02,0xB0,0x02, +/* 45 parameter read value (60Hz) */ +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, +/* level2_key Disable */ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0xA5,0xA5 +}, + +{ +/* Level2 key Enable */ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0x5A,0x5A, +/* 135 parameter read value (90Hz) */ +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, +/* 180 parameter read value (90Hz) */ +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_S6E3FC2X01; +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); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (!strcmp(panel->type, "primary")) + goto error; + rc = 0; + } else +#endif + 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->poc)) { + rc = gpio_request(panel->poc, "platform_poc_gpio"); + if (rc) { + DSI_ERR("request for platform_poc_gpio failed, rc=%d\n", rc); + goto error_release_lcd_mode_sel; + } + } + + if (gpio_is_valid(panel->vddr_gpio)) { + rc = gpio_request(panel->vddr_gpio, "vddr_gpio"); + if (rc) { + DSI_ERR("request for vddr_gpio failed, rc=%d\n", rc); + goto error_release_poc; + } + } + + if (gpio_is_valid(panel->vddd_gpio)) { + rc = gpio_request(panel->vddd_gpio, "vddd_gpio"); + if (rc) { + DSI_ERR("request for vddd_gpio failed, rc=%d\n", rc); + goto error_release_vddr; + } + } + + if (gpio_is_valid(panel->tp1v8_gpio)) { + rc = gpio_request(panel->tp1v8_gpio, "tp1v8_gpio"); + if (rc) { + DSI_ERR("request for tp1v8_gpio failed, rc=%d\n", rc); + goto error_release_vddd; + } + } + + if (gpio_is_valid(panel->panel_test_gpio)) { + rc = gpio_request(panel->panel_test_gpio, "panel_test_gpio"); + if (rc) { + DSI_ERR("request for panel_test_gpio failed, rc=%d\n", + rc); + panel->panel_test_gpio = -1; + rc = 0; + goto error_release_tp1v8_gpio; + } + } + + goto error; +error_release_tp1v8_gpio: + if (gpio_is_valid(panel->tp1v8_gpio)) + gpio_free(panel->tp1v8_gpio); +error_release_vddd: + if (gpio_is_valid(panel->vddd_gpio)) + gpio_free(panel->vddd_gpio); +error_release_vddr: + if (gpio_is_valid(panel->vddr_gpio)) + gpio_free(panel->vddr_gpio); +error_release_poc: + if (gpio_is_valid(panel->poc)) + gpio_free(panel->poc); +error_release_lcd_mode_sel: + if (gpio_is_valid(r_config->lcd_mode_sel_gpio)) + gpio_free(r_config->lcd_mode_sel_gpio); +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->poc)) + gpio_free(panel->poc); + + if (gpio_is_valid(panel->vddr_gpio)) + gpio_free(panel->vddr_gpio); + + if (gpio_is_valid(panel->vddd_gpio)) + gpio_free(panel->vddd_gpio); + + if (gpio_is_valid(panel->tp1v8_gpio)) + gpio_free(panel->tp1v8_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); + 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 defined(CONFIG_PXLW_IRIS) + if (iris_is_dual_supported() && panel->is_secondary) + return rc; + + iris_reset(); +#endif + + 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); + DSI_ERR("enable pwr regulator\n"); + if (rc) { + DSI_ERR("[%s] failed to enable vregs, rc=%d\n", + panel->name, rc); + goto exit; + } + + if (gpio_is_valid(panel->poc)) { + rc = gpio_direction_output(panel->poc, 1); + DSI_ERR("enable poc gpio\n"); + if (rc) { + DSI_ERR("unable to set dir for poc gpio rc=%d\n", rc); + goto error_disable_vregs; + } + } + + if (gpio_is_valid(panel->vddr_gpio)) { + rc = gpio_direction_output(panel->vddr_gpio, 1); + DSI_ERR("enable vddr gpio\n"); + if (rc) { + DSI_ERR("unable to set dir for vddr gpio rc=%d\n", rc); + goto error_disable_poc; + } + } + + if (gpio_is_valid(panel->vddd_gpio)) { + rc = gpio_direction_output(panel->vddd_gpio, 1); + DSI_ERR("enable vddd gpio\n"); + if (rc) { + DSI_ERR("unable to set dir for vddd gpio rc=%d\n", rc); + goto error_disable_vddr; + } + } + + rc = dsi_panel_set_pinctrl_state(panel, true); + DSI_ERR("set dsi panel pinctrl state true\n"); + if (rc) { + DSI_ERR("[%s] failed to set pinctrl, rc=%d\n", panel->name, rc); + goto error_disable_vddd; + } + + rc = dsi_panel_reset(panel); + DSI_ERR("reset panel\n"); + 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); +//error_disable_pinctrl: + (void)dsi_panel_set_pinctrl_state(panel, false); + +error_disable_vddd: + if (gpio_is_valid(panel->vddd_gpio)) + gpio_set_value(panel->vddd_gpio, 0); + +error_disable_vddr: + if (gpio_is_valid(panel->vddr_gpio)) + gpio_set_value(panel->vddr_gpio, 0); + +error_disable_poc: + if (gpio_is_valid(panel->poc)) + gpio_set_value(panel->poc, 0); + +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)) { + gpio_set_value(panel->reset_config.reset_gpio, 0); + DSI_ERR("disable reset gpio\n"); + } + +#if defined(CONFIG_PXLW_IRIS) + iris_power_off(panel); +#endif + + if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) + gpio_set_value(panel->reset_config.lcd_mode_sel_gpio, 0); + + rc = dsi_panel_set_pinctrl_state(panel, false); + DSI_ERR("set dsi panel pinctrl state false\n"); + if (rc) { + DSI_ERR("[%s] failed set pinctrl state, rc=%d\n", panel->name, + rc); + } + + if ((strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) + || (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") == 0)) { + msleep(10); + } else { + msleep(1); + } + + if (gpio_is_valid(panel->vddd_gpio)) { + gpio_set_value(panel->vddd_gpio, 0); + DSI_ERR("disable vddd gpio\n"); + } + + if (gpio_is_valid(panel->vddr_gpio)) { + gpio_set_value(panel->vddr_gpio, 0); + DSI_ERR("disable vddr gpio\n"); + msleep(1); + } + + if (gpio_is_valid(panel->poc)) { + gpio_set_value(panel->poc, 0); + DSI_ERR("disable poc gpio\n"); + } + + 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_pwr_enable_regulator(&panel->power_info, false); + DSI_ERR("disable dsi pwr regulator\n"); + 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) { + DSI_ERR("Invalid params\n"); + 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; + } + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) { + rc = iris_pt_send_panel_cmd(panel, &(mode->priv_info->cmd_sets[type])); + if (rc) + DSI_ERR("iris_pt_send_panel_cmd failed\n"); + return rc; + } +#endif + 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; +} +EXPORT_SYMBOL(dsi_panel_tx_cmd_set); + +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; + 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; + + /*xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, add for fingerprint*/ + if (panel->is_hbm_enabled) { + hbm_finger_print = true; + DSI_ERR("HBM is enabled\n"); + return 0; + } + + /*** DC backlight config ****/ + 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; + } + } +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) + rc = iris_update_backlight(1, bl_lvl); + else +#endif + 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 defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) + rc = iris_update_backlight(1, bl_lvl); + else +#endif + 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); + if (dsi_panel_name == DSI_PANEL_SAMSUNG_AMB655XL) { + if (mode_fps == 120) + mdelay(9); + else + mdelay(17); + } + } + 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->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-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-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-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-new-command", + "qcom,mdss-dsi-panel-aod-off-samsung-command", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command", + "qcom,mdss-dsi-panel-real-aod-off-hbm-on-command", + "qcom,mdss-dsi-panel-hbm-off-aod-on-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-display-srgb-color-mode-on-command", + "qcom,mdss-dsi-panel-display-srgb-color-mode-off-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-dci-p3-on-command", + "qcom,mdss-dsi-panel-dci-p3-off-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-night-mode-on-command", + "qcom,mdss-dsi-panel-night-mode-off-command", + + "qcom,mdss-dsi-acl-command", + "qcom,mdss-dsi-loading-effect-enable-command", + "qcom,mdss-dsi-loading-effect-disable-command", + "qcom,mdss-dsi-mca-setting-mode-1-command", + "qcom,mdss-dsi-mca-setting-mode-0-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-otp-read-c8-smrps-command", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command", + "qcom,mdss-dsi-panel-gamma-change-write-command", + + "qcom,mdss-dsi-panel-id-command", + "qcom,mdss-dsi-panel-read-register-ed-command", + "qcom,mdss-113mhz-osc-dsi-on-command", + "qcom,mdss-dsi-post-on-backlight", + "qcom,mdss-dsi-seed-command", + "qcom,mdss-dsi-panel-command", + "qcom,mdss-dsi-panel-register-read-command", + "qcom,mdss-dsi-panel-level2-key-enable-command", + "qcom,mdss-dsi-panel-level2-key-disable-command", +#if defined(CONFIG_PXLW_IRIS) + "iris,abyp-panel-command", +#endif +}; + +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-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-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-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-new-command-state", + "qcom,mdss-dsi-panel-aod-off-samsung-command-state", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command-state", + "qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state", + "qcom,mdss-dsi-panel-hbm-off-aod-on-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-display-srgb-color-mode-on-command-state", + "qcom,mdss-dsi-panel-display-srgb-color-mode-off-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-dci-p3-on-command-state", + "qcom,mdss-dsi-panel-dci-p3-off-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-night-mode-on-command-state", + "qcom,mdss-dsi-panel-night-mode-off-command-state", + + "qcom,mdss-dsi-acl-command-state", + "qcom,mdss-dsi-loading-effect-enable-command-state", + "qcom,mdss-dsi-loading-effect-disable-command-state", + "qcom,mdss-dsi-mca-setting-mode-1-command-state", + "qcom,mdss-dsi-mca-setting-mode-0-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-otp-read-c8-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-change-write-command-state", + + "qcom,mdss-dsi-panel-id-command-state", + "qcom,mdss-dsi-panel-read-register-ed-command-state", + "qcom,mdss-113mhz-osc-dsi-on-command-state", + "qcom,mdss-dsi-post-on-backlight-state", + "qcom,mdss-dsi-seed-command-state", + "qcom,mdss-dsi-panel-command-state", + "qcom,mdss-dsi-panel-register-read-command-state", + "qcom,mdss-dsi-panel-level2-key-enable-command-state", + "qcom,mdss-dsi-panel-level2-key-disable-command-state", +#if defined(CONFIG_PXLW_IRIS) + "iris,abyp-panel-command-state", +#endif +}; + +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; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + set->state = DSI_CMD_SET_STATE_HS; +#endif + } 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 defined(CONFIG_PXLW_IRIS) + bool is_primary = false; +#endif + + if (!strcmp(panel->type, "primary")) { + reset_gpio_name = "qcom,platform-reset-gpio"; + mode_set_gpio_name = "qcom,panel-mode-gpio"; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + is_primary = true; +#endif + } 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) { +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (is_primary) { + rc = panel->reset_config.reset_gpio; + DSI_ERR("[%s] failed get primary reset gpio, rc=%d\n", panel->name, rc); + goto error; + } + } else { +#endif + rc = panel->reset_config.reset_gpio; + DSI_ERR("[%s] failed get reset gpio, rc=%d\n", panel->name, rc); + goto error; +#if defined(CONFIG_PXLW_IRIS) + } +#endif + } + + 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->poc = utils->get_named_gpio(utils->data, "qcom,platform-poc-gpio", 0); + if (!gpio_is_valid(panel->poc)) { + DSI_DEBUG("[%s] platform-poc-gpio is not set, rc=%d\n", + panel->name, rc); + } + + panel->vddr_gpio = utils->get_named_gpio(utils->data, "qcom,vddr-gpio", 0); + if (!gpio_is_valid(panel->vddr_gpio)) { + DSI_DEBUG("[%s] vddr-gpio is not set, rc=%d\n", + panel->name, rc); + } + + if(get_prj_version() == 14) { + panel->vddd_gpio = utils->get_named_gpio(utils->data, "qcom,vddd-gpio", 0); + DSI_DEBUG("panel->vddd_gpio = %d\n",panel->vddd_gpio); + if (!gpio_is_valid(panel->vddd_gpio)) { + DSI_DEBUG("[%s] vddd-gpio is not set, rc=%d\n", + panel->name, rc); + } + } else { + panel->vddd_gpio = -EINVAL; + DSI_DEBUG("panel->vddd_gpio = %d\n",panel->vddd_gpio); + } + + panel->tp1v8_gpio = utils->get_named_gpio(utils->data, "qcom,tp1v8-gpio", 0); + if (!gpio_is_valid(panel->tp1v8_gpio)) { + DSI_DEBUG("[%s] tp1v8_gpio is not set, rc=%d\n", + panel->name, rc); + } + + panel->err_flag_gpio = utils->get_named_gpio(utils->data, "qcom,err-flag-gpio", 0); + if (!gpio_is_valid(panel->err_flag_gpio)) { + DSI_DEBUG("[%s] err_flag_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; + } + + 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; +#if defined(CONFIG_PXLW_IRIS) + else if (iris_is_chip_supported() && dsc->bpc == 10 && dsc->bpp == 10) + dsc->first_line_bpg_offset = 9; +#endif + 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]; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && ratio_index == DSC_10BPC_10BPP) + dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1_pxlw; +#endif + } + 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 = 0; + static const char *panel_manufacture; + static const char *panel_version; + static const char *backlight_manufacture; + static const char *backlight_version; + + DSI_DEBUG("start\n"); + + panel->mca_setting_mode = 1; + DSI_DEBUG("Mca setting mode = %d\n", panel->mca_setting_mode); + + panel->panel_mismatch_check = + of_property_read_bool(of_node, "qcom,mdss-panel-mismatch-check"); + DSI_DEBUG("panel_mismatch_check:%d\n", panel->panel_mismatch_check); + + panel->lp11_init = + of_property_read_bool(of_node, "qcom,mdss-dsi-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"); + 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"); + DSI_DEBUG("naive_display_loading_effect_mode:%d\n", panel->naive_display_loading_effect_mode); + + panel_manufacture = of_get_property(of_node, + "qcom,mdss-dsi-panel-manufacture", NULL); + if (!panel_manufacture) + DSI_ERR("panel manufacture is not specified\n"); + panel_version = of_get_property(of_node, + "qcom,mdss-dsi-panel-version", NULL); + if (!panel_version) + DSI_ERR("panel version is not specified\n"); + 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("backlight manufacture is not specified\n"); + backlight_version = of_get_property(of_node, + "qcom,mdss-dsi-backlight-version", NULL); + if (!backlight_version) + DSI_ERR("backlight version is not specified\n"); + push_component_info(BACKLIGHT, (char *)backlight_version, (char *)backlight_manufacture); + + 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); + + DSI_DEBUG("end\n"); + 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 (!panel->name) + panel->name = DSI_PANEL_DEFAULT_LABEL; + else if (strcmp(panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_S6E3HC2; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_S6E3HC2"); + } else if (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_SOFEF03F_M; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_SOFEF03F_M"); + } else if (strcmp(panel->name, "samsung s6e3fc2x01 cmd mode dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_S6E3FC2X01; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_S6E3FC2X01"); + } else if (strcmp(panel->name, "samsung 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 ana6706 dsc cmd mode panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_ANA6706; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_ANA6706"); + } else if (strcmp(panel->name, "samsung amb655x fhd cmd mode dsc dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_AMB655XL; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_AMB655XL"); + } + +#if defined(CONFIG_PXLW_IRIS) + iris_query_capability(panel); +#endif + + /* + * 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); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (!strcmp(panel->type, "primary")) + goto error_pinctrl_deinit; + rc = 0; + } else +#endif + 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; + } + + if (panel->err_flag_status == true) { + DSI_ERR("no need to power on when err flag irq comes\n"); + panel->err_flag_status = false; + return rc; + } + + mutex_lock(&panel->panel_lock); + +#if defined(CONFIG_PXLW_IRIS) + iris_power_on(panel); +#endif + /* If LP11_INIT is set, panel will be powered up during prepare() */ + if (panel->lp11_init) + goto error; + + if (gpio_is_valid(panel->tp1v8_gpio)) { + rc = gpio_direction_output(panel->tp1v8_gpio, 1); + DSI_ERR("enable tp1v8 gpio\n"); + if (rc) + DSI_ERR("unable to set dir for tp1v8 gpio rc=%d\n", rc); + } + + rc = dsi_panel_power_on(panel); + if (rc) { + DSI_ERR("[%s] panel power on failed, rc=%d\n", panel->name, rc); + if (gpio_is_valid(panel->tp1v8_gpio)) + gpio_set_value(panel->tp1v8_gpio, 0); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (iris_vdd_valid()) + iris_disable_vdd(); + else + iris_control_pwr_regulator(false); + } +#endif + 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; + SDE_ATRACE_BEGIN("dsi_panel_update_pps"); + + if (!panel || !panel->cur_mode) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_dual_supported() && panel->is_secondary) + return rc; +#endif + mutex_lock(&panel->panel_lock); + + priv_info = panel->cur_mode->priv_info; + + set = &priv_info->cmd_sets[DSI_CMD_SET_PPS]; + SDE_ATRACE_BEGIN("dsi_dsc_create_pps_buf_cmd"); + dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0); + SDE_ATRACE_END("dsi_dsc_create_pps_buf_cmd"); + SDE_ATRACE_BEGIN("dsi_panel_create_cmd_packets"); + rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd, + DSI_CMD_PPS_SIZE, 1, set->cmds); + SDE_ATRACE_END("dsi_panel_create_cmd_packets"); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error; + } + SDE_ATRACE_BEGIN("dsi_panel_tx_cmd_set"); +#if 0 + DSI_ERR("qcom pps table:\n"); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, + set->cmds->msg.tx_buf, set->cmds->msg.tx_len, false); +#endif + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) + rc = iris_pt_send_panel_cmd(panel, &(panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_PPS])); + else +#endif + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PPS); + + SDE_ATRACE_END("dsi_panel_tx_cmd_set"); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n", + panel->name, rc); + } + + SDE_ATRACE_BEGIN("dsi_panel_destroy_cmd_packets"); + dsi_panel_destroy_cmd_packets(set); + SDE_ATRACE_END("dsi_panel_destroy_cmd_packets"); +error: + mutex_unlock(&panel->panel_lock); + SDE_ATRACE_END("dsi_panel_update_pps"); + 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 (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; + } + } + + 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); + + 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 defined(CONFIG_PXLW_IRIS) + if (iris_is_dual_supported() && panel->is_secondary) + return rc; +#endif + 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); + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + rc = iris_switch(panel, + &(panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_TIMING_SWITCH]), + &panel->cur_mode->timing); + } else +#endif + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH); + DSI_ERR("Send DSI_CMD_SET_TIMING_SWITCH cmds\n"); + 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); + + if((strcmp(panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) && (gamma_read_flag == GAMMA_READ_SUCCESS)) { + if (mode_fps == 90) { + rc = dsi_panel_tx_gamma_cmd_set(panel, DSI_GAMMA_CMD_SET_SWITCH_90HZ); + DSI_ERR("Send DSI_GAMMA_CMD_SET_SWITCH_90HZ cmds\n"); + if (rc) + DSI_ERR("[%s] Failed to send DSI_GAMMA_CMD_SET_SWITCH_90HZ cmds, rc=%d\n", + panel->name, rc); + } + else { + rc = dsi_panel_tx_gamma_cmd_set(panel, DSI_GAMMA_CMD_SET_SWITCH_60HZ); + DSI_ERR("Send DSI_GAMMA_CMD_SET_SWITCH_60HZ cmds\n"); + if (rc) + DSI_ERR("[%s] Failed to send DSI_GAMMA_CMD_SET_SWITCH_60HZ cmds, rc=%d\n", + panel->name, rc); + } + } + + 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; + } + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_dual_supported() && panel->is_secondary) + return rc; +#endif + panel->panel_switch_status = true; + mutex_lock(&panel->panel_lock); + +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + rc = iris_post_switch(panel, + &(panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_POST_TIMING_SWITCH]), + &panel->cur_mode->timing); + } else +#endif + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH); + DSI_ERR("Send DSI_CMD_SET_POST_TIMING_SWITCH cmds\n"); + 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; + } + DSI_ERR("start\n"); + + 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; + } + + if (strcmp(panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) { + if ((panel->panel_stage_info == EVT2_113MHZ_OSC) || (panel->panel_stage_info == PVT_113MHZ_OSC) + || (panel->panel_stage_info == PVT_113MHZ_OSC_XTALK) || (panel->panel_code_info == 0xEE)) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_113MHZ_OSC_ON); + DSI_ERR("Send DSI_CMD_SET_113MHZ_OSC_ON cmds\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON); + DSI_ERR("Send DSI_CMD_SET_ON cmds\n"); + } + } else { +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + rc = iris_enable(panel, &(panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_ON])); + else +#endif + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON); + DSI_ERR("Send DSI_CMD_SET_ON cmds\n"); + } + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_ON cmds, rc=%d\n", + panel->name, rc); + else + panel->panel_initialized = true; + + rc = dsi_panel_dimming_gamma_write(panel); + if (rc) + DSI_ERR("Failed to write dimming gamma, rc=%d\n", rc); + + if (panel->mca_setting_mode == 0) { + rc = dsi_panel_set_mca_setting_mode(panel, panel->mca_setting_mode); + if (rc) + DSI_ERR("Failed to set mca setting mode %d, rc=%d\n", panel->mca_setting_mode, rc); + } + + if ((strcmp(panel->name, "samsung dsc cmd mode oneplus dsi panel") == 0) && (gamma_read_flag == GAMMA_READ_SUCCESS)) { + if (mode_fps == 60) { + rc = dsi_panel_tx_gamma_cmd_set(panel, DSI_GAMMA_CMD_SET_SWITCH_60HZ); + DSI_ERR("Send DSI_GAMMA_CMD_SET_SWITCH_60HZ cmds\n"); + if (rc) + DSI_ERR("[%s] Failed to send DSI_GAMMA_CMD_SET_SWITCH_60HZ cmds, rc=%d\n", + panel->name, rc); + } + } + + 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; + } + +#if defined(CONFIG_PXLW_IRIS) + if (panel->is_secondary) { + mutex_unlock(&panel->panel_lock); + return rc; + } +#endif + + mutex_unlock(&panel->panel_lock); + DSI_ERR("end\n"); + + /* remove print actvie ws */ + pm_print_active_wakeup_sources_queue(false); + + 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; + } + + DSI_ERR("start\n"); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_dual_supported() && panel->is_secondary) + return rc; +#endif + 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 defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + iris_disable(panel, NULL); +#endif + 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; + } + 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); + DSI_ERR("end\n"); + + /* remove print actvie ws */ + pm_print_active_wakeup_sources_queue(true); + + 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; + } + + if (panel->err_flag_status == true) { + DSI_ERR("no need to power off when err flag irq comes\n"); + return rc; + } + + 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); + } + + if (!tp_1v8_power) { + if (gpio_is_valid(panel->tp1v8_gpio)) { + gpio_set_value(panel->tp1v8_gpio, 0); + DSI_ERR("disable tp1v8 gpio\n"); + } + } + + 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); + if (dsi_panel_name == DSI_PANEL_SAMSUNG_AMB655XL) { + if (mode_fps == 120) + mdelay(9); + else + mdelay(17); + } + } + 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 (strcmp(panel->name, "samsung sofef03f_m fhd cmd mode dsc dsi panel") == 0) + level = level + 1023; + else if (strcmp(panel->name, "BOE dsc cmd mode oneplus dsi panel") == 0) + level = level + 3072; + else if (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") == 0) + level = level + 2048; + else if (strcmp(panel->name, "samsung ana6705 fhd cmd mode dsc dsi panel") == 0) { + 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; + } +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported() && iris_is_pt_mode(panel)) + rc = iris_update_backlight(1, level); + else + rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, level); +#else + rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, level); +#endif + 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) { + 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); + DSI_ERR("Native Display p3 Mode On.\n"); + } 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) { + 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); + DSI_ERR("Native wide color Mode On.\n"); + } 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) { + 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); + DSI_ERR("Native srgb color Mode On.\n"); + } 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) { + 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); + DSI_ERR("turn on customer srgb\n"); + } 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) { + 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); + DSI_ERR("turn on customer P3\n"); + } 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_set_mca_setting_mode(struct dsi_panel *panel, int mca_setting_mode) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") != 0) { + return 0; + } + + if (!panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mode = panel->cur_mode; + + if (mca_setting_mode == 1) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_MCA_SETTING_MODE_1].count; + if (!count) { + DSI_ERR("This panel does not support mca setting mode 1\n"); + rc = -EINVAL; + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MCA_SETTING_MODE_1); + if (rc) + DSI_ERR("Failed to send DSI_CMD_SET_MCA_SETTING_MODE_1 cmds\n"); + DSI_ERR("Send DSI_CMD_SET_MCA_SETTING_MODE_1 cmds\n"); + } + } else if (mca_setting_mode == 0) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_MCA_SETTING_MODE_0].count; + if (!count) { + DSI_ERR("This panel does not support mca setting mode 0\n"); + rc = -EINVAL; + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MCA_SETTING_MODE_0); + if (rc) + DSI_ERR("Failed to send DSI_CMD_SET_MCA_SETTING_MODE_0 cmds\n"); + DSI_ERR("Send DSI_CMD_SET_MCA_SETTING_MODE_0 cmds\n"); + } + } + +error: + 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; +} + +void dsi_panel_update_gamma_change_write(void) +{ + int r_4 = 0; + int g_4 = 0; + int b_4 = 0; + int r_3 = 0; + int g_3 = 0; + int b_3 = 0; + int r_2 = 0; + int g_2 = 0; + int b_2 = 0; + int r_1 = 0; + int g_1 = 0; + int b_1 = 0; + + r_4 = ((dimming_gamma_120hz[4] & 0xC0) << 2) | dimming_gamma_120hz[0]; + if (r_4 < 0) { + r_4 = 0; + DSI_ERR("2nit 120hz: r_4 = 0"); + } + g_4 = ((dimming_gamma_120hz[4] & 0x30) << 4) | dimming_gamma_120hz[1]; + if (g_4 < 0) { + g_4 = 0; + DSI_ERR("2nit 120hz: g_4 = 0"); + } + b_4 = ((dimming_gamma_120hz[4] & 0x0C) << 6) | dimming_gamma_120hz[2]; + if (b_4 < 0) { + b_4 = 0; + DSI_ERR("2nit 120hz: b_4 = 0"); + } + r_3 = r_4 - 48; + if (r_3 < 0) { + r_3 = 0; + DSI_ERR("2nit 120hz: r_3 = 0"); + } + g_3 = g_4 - 12; + if (g_3 < 0) { + g_3 = 0; + DSI_ERR("2nit 120hz: g_3 = 0"); + } + b_3 = b_4 - 24; + if (b_3 < 0) { + b_3 = 0; + DSI_ERR("2nit 120hz: b_3 = 0"); + } + r_2 = r_4 - 79; + if (r_2 < 0) { + r_2 = 0; + DSI_ERR("2nit 120hz: r_2 = 0"); + } + g_2 = g_4 - 20; + if (g_2 < 0) { + g_2 = 0; + DSI_ERR("2nit 120hz: g_2 = 0"); + } + b_2 = b_4 - 40; + if (b_2 < 0) { + b_2 = 0; + DSI_ERR("2nit 120hz: b_2 = 0"); + } + r_1 = r_4 - 126; + if (r_1 < 0) { + r_1 = 0; + DSI_ERR("2nit 120hz: r_1 = 0"); + } + g_1 = g_4 - 32; + if (g_1 < 0) { + g_1 = 0; + DSI_ERR("2nit 120hz: g_1 = 0"); + } + b_1 = b_4 - 63; + if (b_1 < 0) { + b_1 = 0; + DSI_ERR("2nit 120hz: b_1 = 0"); + } + dimming_gamma_120hz[3] = r_3 & 0xFF; + dimming_gamma_120hz[4] = (dimming_gamma_120hz[4] & 0xFC) | ((r_3 & 0x0300) >> 8); + dimming_gamma_120hz[5] = g_3 & 0xFF; + dimming_gamma_120hz[6] = b_3 & 0xFF; + dimming_gamma_120hz[7] = r_2 & 0xFF; + dimming_gamma_120hz[8] = g_2 & 0xFF; + dimming_gamma_120hz[9] = ((g_3 & 0x0300) >> 2) | ((b_3 & 0x0300) >> 4) | ((r_2 & 0x0300) >> 6) | ((g_2 & 0x0300) >> 8); + dimming_gamma_120hz[10] = b_2 & 0xFF; + dimming_gamma_120hz[11] = r_1 & 0xFF; + dimming_gamma_120hz[12] = g_1 & 0xFF; + dimming_gamma_120hz[13] = b_1 & 0xFF; + dimming_gamma_120hz[14] = ((b_2 & 0x0300) >> 2) | ((r_1 & 0x0300) >> 4) | ((g_1 & 0x0300) >> 6) | ((b_1 & 0x0300) >> 8); + + r_4 = ((dimming_gamma_60hz[4] & 0xC0) << 2) | dimming_gamma_60hz[0]; + if (r_4 < 0) { + r_4 = 0; + DSI_ERR("2nit 60hz: r_4 = 0"); + } + g_4 = ((dimming_gamma_60hz[4] & 0x30) << 4) | dimming_gamma_60hz[1]; + if (g_4 < 0) { + g_4 = 0; + DSI_ERR("2nit 60hz: g_4 = 0"); + } + b_4 = ((dimming_gamma_60hz[4] & 0x0C) << 6)| dimming_gamma_60hz[2]; + if (b_4 < 0) { + b_4 = 0; + DSI_ERR("2nit 60hz: b_4 = 0"); + } + r_3 = r_4 - 53; + if (r_3 < 0) { + r_3 = 0; + DSI_ERR("2nit 60hz: r_3 = 0"); + } + g_3 = g_4 - 27; + if (g_3 < 0) { + g_3 = 0; + DSI_ERR("2nit 60hz: g_3 = 0"); + } + b_3 = b_4 - 23; + if (b_3 < 0) { + b_3 = 0; + DSI_ERR("2nit 60hz: b_3 = 0"); + } + r_2 = r_4 - 86; + if (r_2 < 0) { + r_2 = 0; + DSI_ERR("2nit 60hz: r_2 = 0"); + } + g_2 = g_4 - 44; + if (g_2 < 0) { + g_2 = 0; + DSI_ERR("2nit 60hz: g_2 = 0"); + } + b_2 = b_4 - 37; + if (b_2 < 0) { + b_2 = 0; + DSI_ERR("2nit 60hz: b_2 = 0"); + } + r_1 = r_4 - 170; + if (r_1 < 0) { + r_1 = 0; + DSI_ERR("2nit 60hz: r_1 = 0"); + } + g_1 = g_4 - 88; + if (g_1 < 0) { + g_1 = 0; + DSI_ERR("2nit 60hz: g_1 = 0"); + } + b_1 = b_4 - 73; + if (b_1 < 0) { + b_1 = 0; + DSI_ERR("2nit 60hz: b_1 = 0"); + } + dimming_gamma_60hz[3] = r_3 & 0xFF; + dimming_gamma_60hz[4] = (dimming_gamma_60hz[4] & 0xFC) | ((r_3 & 0x0300) >> 8); + dimming_gamma_60hz[5] = g_3 & 0xFF; + dimming_gamma_60hz[6] = b_3 & 0xFF; + dimming_gamma_60hz[7] = r_2 & 0xFF; + dimming_gamma_60hz[8] = g_2 & 0xFF; + dimming_gamma_60hz[9] = ((g_3 & 0x0300) >> 2) | ((b_3 & 0x0300) >> 4) | ((r_2 & 0x0300) >> 6) | ((g_2 & 0x0300) >> 8); + dimming_gamma_60hz[10] = b_2 & 0xFF; + dimming_gamma_60hz[11] = r_1 & 0xFF; + dimming_gamma_60hz[12] = g_1 & 0xFF; + dimming_gamma_60hz[13] = b_1 & 0xFF; + dimming_gamma_60hz[14] = ((b_2 & 0x0300) >> 2) | ((r_1 & 0x0300) >> 4) | ((g_1 & 0x0300) >> 6) | ((b_1 & 0x0300) >> 8); + + r_4 = ((dimming_gamma_60hz[19] & 0xC0) << 2) | dimming_gamma_60hz[15]; + if (r_4 < 0) { + r_4 = 0; + DSI_ERR("15nit 60hz: r_4 = 0"); + } + g_4 = ((dimming_gamma_60hz[19] & 0x30) << 4) | dimming_gamma_60hz[16]; + if (g_4 < 0) { + g_4 = 0; + DSI_ERR("15nit 60hz: g_4 = 0"); + } + b_4 = ((dimming_gamma_60hz[19] & 0x0C) << 6)| dimming_gamma_60hz[17]; + if (b_4 < 0) { + b_4 = 0; + DSI_ERR("15nit 60hz: b_4 = 0"); + } + r_3 = r_4 - 55; + if (r_3 < 0) { + r_3 = 0; + DSI_ERR("15nit 60hz: r_3 = 0"); + } + g_3 = g_4 - 23; + if (g_3 < 0) { + g_3 = 0; + DSI_ERR("15nit 60hz: g_3 = 0"); + } + b_3 = b_4 - 42; + if (b_3 < 0) { + b_3 = 0; + DSI_ERR("15nit 60hz: b_3 = 0"); + } + r_2 = r_4 - 195; + if (r_2 < 0) { + r_2 = 0; + DSI_ERR("15nit 60hz: r_2 = 0"); + } + g_2 = g_4 - 30; + if (g_2 < 0) { + g_2 = 0; + DSI_ERR("15nit 60hz: g_2 = 0"); + } + b_2 = b_4 - 53; + if (b_2 < 0) { + b_2 = 0; + DSI_ERR("15nit 60hz: b_2 = 0"); + } + r_1 = r_4 - 245; + if (r_1 < 0) { + r_1 = 0; + DSI_ERR("15nit 60hz: r_1 = 0"); + } + g_1 = g_4 - 52; + if (g_1 < 0) { + g_1 = 0; + DSI_ERR("15nit 60hz: g_1 = 0"); + } + b_1 = b_4 - 84; + if (b_1 < 0) { + b_1 = 0; + DSI_ERR("15nit 60hz: b_1 = 0"); + } + dimming_gamma_60hz[18] = r_3 & 0xFF; + dimming_gamma_60hz[19] = (dimming_gamma_60hz[19] & 0xFC) | ((r_3 & 0x0300) >> 8); + dimming_gamma_60hz[20] = g_3 & 0xFF; + dimming_gamma_60hz[21] = b_3 & 0xFF; + dimming_gamma_60hz[22] = r_2 & 0xFF; + dimming_gamma_60hz[23] = g_2 & 0xFF; + dimming_gamma_60hz[24] = ((g_3 & 0x0300) >> 2) | ((b_3 & 0x0300) >> 4) | ((r_2 & 0x0300) >> 6) | ((g_2 & 0x0300) >> 8); + dimming_gamma_60hz[25] = b_2 & 0xFF; + dimming_gamma_60hz[26] = r_1 & 0xFF; + dimming_gamma_60hz[27] = g_1 & 0xFF; + dimming_gamma_60hz[28] = b_1 & 0xFF; + dimming_gamma_60hz[29] = ((b_2 & 0x0300) >> 2) | ((r_1 & 0x0300) >> 4) | ((g_1 & 0x0300) >> 6) | ((b_1 & 0x0300) >> 8); +} + +int dsi_panel_dimming_gamma_write(struct dsi_panel *panel) +{ + int i = 0; + int rc = 0; + int count = 0; + unsigned char *payload; + struct dsi_display_mode *mode; + struct dsi_cmd_desc *cmds; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (strcmp(panel->name, "samsung ana6706 dsc cmd mode panel") != 0) { + return 0; + } + + mode = panel->cur_mode; + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_CHANGE_WRITE].count; + if (!count) { + DSI_ERR("This panel does not support gamma change write command\n"); + return -EINVAL; + } else { + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_CHANGE_WRITE].cmds; + + payload = (u8 *)cmds[2].msg.tx_buf; + for (i = 1; i < 13; i++) + payload[i] = dimming_gamma_120hz[i+2]; + + payload = (u8 *)cmds[7].msg.tx_buf; + for (i = 1; i < 13; i++) + payload[i] = dimming_gamma_60hz[i+2]; + + payload = (u8 *)cmds[12].msg.tx_buf; + for (i = 1; i < 13; i++) + payload[i] = dimming_gamma_60hz[i+17]; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_CHANGE_WRITE); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_CHANGE_WRITE commands\n"); + } + DSI_ERR("Send DSI_CMD_SET_GAMMA_CHANGE_WRITE cmds.\n"); + } + + 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 100755 index 000000000000..1ac251b6dd8b --- /dev/null +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -0,0 +1,465 @@ +/* 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 EVT2_113MHZ_OSC 0x99 +#define PVT_113MHZ_OSC 0x10 +#define PVT_113MHZ_OSC_XTALK 0x11 + +#define GAMMA_READ_SUCCESS 1 +#define GAMMA_READ_ERROR 0 + +extern u32 mode_fps; +extern int gamma_read_flag; +extern int tp_1v8_power; +extern char dimming_gamma_60hz[30]; +extern char dimming_gamma_120hz[15]; + +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]; + 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; + u64 panel_serial_number; + int panel_code_info; + int panel_stage_info; + int panel_production_info; + int panel_ic_v; + char buf_select[10]; + int panel_tool; + int ddic_x; + int ddic_y; + int ddic_check_info; + + int hbm_backlight; + int hbm_brightness; + int hbm_mode; + bool is_hbm_enabled; + int op_force_screenfp; + bool dim_status; + + int aod_mode; + int aod_status; + int aod_curr_mode; + int aod_disable; + + int seed_lp_mode; + int acl_mode; + int acl_cmd_index; + int acl_mode_index; + int srgb_mode; + int dci_p3_mode; + int night_mode; + int oneplus_mode; + int adaption_mode; + 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; + int mca_setting_mode; + struct delayed_work gamma_read_work; + + int status_value; + int panel_mismatch_check; + int panel_mismatch; + bool panel_switch_status; + bool need_power_on_backlight; + + int poc; + int vddr_gpio; + int vddd_gpio; + int tp1v8_gpio; + int err_flag_gpio; + bool is_err_flag_irq_enabled; + bool err_flag_status; + + 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 power_mode; + + int panel_test_gpio; +#if defined(CONFIG_PXLW_IRIS) + bool is_secondary; +#endif + 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); +int dsi_panel_set_mca_setting_mode(struct dsi_panel *panel, int mca_setting_mode); +void dsi_panel_update_gamma_change_write(void); +int dsi_panel_dimming_gamma_write(struct dsi_panel *panel); +#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 100755 index 000000000000..cef5fe70cf5d --- /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 100755 index 000000000000..949de1b4b02e --- /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 100755 index 000000000000..4115138bb32a --- /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 100755 index 000000000000..6643a940c198 --- /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 100755 index 000000000000..b550ee720cad --- /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 100755 index 000000000000..5ee1de16c62a --- /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 100755 index 000000000000..a863827050ad --- /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 100755 index 000000000000..538d0ef73f9b --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_hw_v4_0.c @@ -0,0 +1,836 @@ +// 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; + DSI_PHY_DBG(phy, "bit_clk_rate_hz = %d\n", cfg->bit_clk_rate_hz); + + 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; + if ((cfg->bit_clk_rate_hz == 1452000000) || (cfg->bit_clk_rate_hz == 825600000)) { + glbl_str_swi_cal_sel_ctrl = 0x03; + glbl_hstx_str_ctrl_0 = 0xee; + } else { + glbl_str_swi_cal_sel_ctrl = 0x00; + glbl_hstx_str_ctrl_0 = 0x88; + } + DSI_PHY_DBG(phy, "glbl_str_swi_cal_sel_ctrl = %d\n", glbl_str_swi_cal_sel_ctrl); + DSI_PHY_DBG(phy, "glbl_hstx_str_ctrl_0 = %d\n", glbl_hstx_str_ctrl_0); + } 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 100755 index 000000000000..655b81780594 --- /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 100755 index 000000000000..536e7670a129 --- /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 100755 index 000000000000..383999395bcd --- /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 100755 index 000000000000..c57b6b5ff28d --- /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 100755 index 000000000000..112762896a60 --- /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 100755 index 000000000000..bcaefaf98acf --- /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 100755 index 000000000000..fd9ef2c18d8b --- /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/dsi/iris/dsi_iris5.h b/techpack/display/msm/dsi/iris/dsi_iris5.h new file mode 100755 index 000000000000..7d045763f7aa --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_H_ +#define _DSI_IRIS_H_ + +#include "dsi_iris5_def.h" + + +void iris_set_cfg_index(int index); +int iris_parse_param(struct dsi_display *display); +void iris_init(struct dsi_display *display, struct dsi_panel *panel); + +int iris_get_abyp_mode(struct dsi_panel *panel); + +int iris_operate_conf(struct msm_iris_operate_value *argp); +int iris_operate_tool(struct msm_iris_operate_value *argp); + +int iris_get_hdr_enable(void); +bool iris_dspp_dirty(void); + +int iris_prepare_for_kickoff(void *phys_enc); +int iris_kickoff(void *phys_enc); + +int iris_sync_panel_brightness(int32_t step, void *phys_enc); + +#endif // _DSI_IRIS_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_api.h b/techpack/display/msm/dsi/iris/dsi_iris5_api.h new file mode 100755 index 000000000000..8167aa48d76d --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_api.h @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_API_H_ +#define _DSI_IRIS_API_H_ + +#include "dsi_display.h" + +void iris_deinit(struct dsi_display *display); +void iris_power_on(struct dsi_panel *panel); +void iris_reset(void); +void iris_power_off(struct dsi_panel *panel); +int iris_pt_send_panel_cmd(struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset); +int iris_enable(struct dsi_panel *panel, struct dsi_panel_cmd_set *on_cmds); +int iris_disable(struct dsi_panel *panel, struct dsi_panel_cmd_set *off_cmds); +int iris_post_switch(struct dsi_panel *panel, + struct dsi_panel_cmd_set *switch_cmds, + struct dsi_mode_info *mode_info); +int iris_switch(struct dsi_panel *panel, + struct dsi_panel_cmd_set *switch_cmds, + struct dsi_mode_info *mode_info); +int iris_read_status(struct dsi_display_ctrl *ctrl, struct dsi_panel *panel); +int iris_get_status(void); +int iris_set_aod(struct dsi_panel *panel, bool aod); +bool iris_get_aod(struct dsi_panel *panel); +int iris_set_fod(struct dsi_panel *panel, bool fod); +int iris_post_fod(struct dsi_panel *panel); + +void iris_send_cont_splash(struct dsi_display *display); +bool iris_is_pt_mode(struct dsi_panel *panel); +void iris_prepare(struct dsi_display *display); + +int iris_update_backlight(u8 pkg_mode, u32 bl_lvl); +void iris_control_pwr_regulator(bool on); +int iris_panel_ctrl_read_reg(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, u8 *rx_buf, int rlen, + struct dsi_cmd_desc *cmd); + +bool iris_secondary_display_autorefresh(void *phys_enc); +bool iris_is_virtual_encoder_phys(void *phys_enc); +void iris_register_osd_irq(void *disp); +void iris_inc_osd_irq_cnt(void); + +void iris_query_capability(struct dsi_panel *panel); +bool iris_is_chip_supported(void); +bool iris_is_softiris_supported(void); +bool iris_is_dual_supported(void); + +void iris_sde_plane_setup_csc(void *csc_ptr); +int iris_sde_kms_iris_operate(struct msm_kms *kms, + u32 operate_type, struct msm_iris_operate_value *operate_value); +void iris_sde_update_dither_depth_map(uint32_t *map); +void iris_sde_prepare_for_kickoff(uint32_t num_phys_encs, void *phys_enc); +void iris_sde_encoder_sync_panel_brightness(uint32_t num_phys_encs, + void *phys_enc); +void iris_sde_encoder_kickoff(uint32_t num_phys_encs, void *phys_enc); +void iris_sde_encoder_wait_for_event(uint32_t num_phys_encs, + void *phys_enc, uint32_t event); + +int msm_ioctl_iris_operate_conf(struct drm_device *dev, void *data, + struct drm_file *file); +int msm_ioctl_iris_operate_tool(struct drm_device *dev, void *data, + struct drm_file *file); + +void iris_dsi_display_res_init(struct dsi_display *display); +void iris_dsi_display_debugfs_init(struct dsi_display *display, + struct dentry *dir, struct dentry *dump_file); +void iris_dsi_panel_dump_pps(struct dsi_panel_cmd_set *set); +void iris_dsi_ctrl_dump_desc_cmd(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg); + +void iris_sde_hw_sspp_setup_csc_v2(void *pctx, const void *pfmt, void *pdata); + +#endif // _DSI_IRIS_API_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_cmds.c b/techpack/display/msm/dsi/iris/dsi_iris5_cmds.c new file mode 100755 index 000000000000..42e513125a47 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_cmds.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <drm/drm_mipi_dsi.h> +#include <video/mipi_display.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" + +//#define IRIS_DSC +//#define IRIS_PARTIAL_UPDATE +char iris_panel_off_cmds0_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x05, 0x28, 0x00, 0x03, +}; +char iris_panel_off_cmds1_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x05, 0x10, 0x00, 0x03, +}; + +char iris_mipi_rx_phy_cmds_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x08, 0x00, 0x04, 0xf0, 0x80, 0x02, 0x5c, 0x00, 0x08, 0x08, 0x04, 0xf0, + 0x00, 0x02, 0x02, 0x0e, 0x10, 0x09, 0x04, 0xf0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0xf0, + 0x60, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x04, 0xf0, 0x4e, 0x00, 0x02, 0x00, 0x10, 0x0a, 0x04, 0xf0, + 0x4e, 0x00, 0x02, 0x00, 0x18, 0x0a, 0x04, 0xf0, 0x4e, 0x00, 0x02, 0x00, 0x20, 0x0a, 0x04, 0xf0, + 0x4e, 0x00, 0x02, 0x00, 0x28, 0x0a, 0x04, 0xf0, 0x4e, 0x00, 0x16, 0x00, +}; + +char iris_sys_cmds0_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf0, 0x0f, 0x82, 0x02, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xf9, 0x00, 0x00, 0x00, +}; + +char iris_sys_cmds1_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, +}; + +char iris_sys_cmds2_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xf0, + 0x2d, 0x58, 0xa1, 0x00, 0x64, 0x00, 0x00, 0xf0, 0x0b, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0xf0, + 0x17, 0x80, 0x0a, 0x00, 0x14, 0x00, 0x00, 0xf0, 0xf1, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0xf0, + 0xf8, 0x00, 0x00, 0x00, +}; + +char iris_sys_cmds3_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, +}; + +char iris_sys_cmds4_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x02, 0x00, +}; + +char iris_sys_cmds5_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x34, 0x00, 0x00, 0xf0, 0x2d, 0x5c, 0xa1, 0x00, 0x1c, 0x00, 0x00, 0xf0, + 0x18, 0xf0, 0xe0, 0x01, 0x14, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0xf0, + 0x00, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0xf0, 0x18, 0xf8, 0xe0, 0x01, 0x1c, 0x00, 0x00, 0xf0, + 0x18, 0xf0, 0xe0, 0x01, +}; + +char iris_sys_cmds6_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x34, 0x00, 0x00, 0xf0, 0x19, 0x78, 0xa2, 0x00, 0x64, 0x00, 0x00, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfc, 0x00, 0x02, 0x00, +}; + +char iris_sys_misc_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x28, 0x00, 0x00, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0xf0, + 0x3f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0, 0x80, 0x81, 0x00, 0x00, 0x4c, 0x00, 0x00, 0xf0, + 0x00, 0xd4, 0x00, 0x00, +}; + +char iris_sys_te_dly_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x48, 0x00, 0x00, 0xf0, 0x80, 0x81, 0x00, 0x00, 0x4c, 0x00, 0x00, 0xf0, + 0x00, 0xd4, 0x00, 0x00, 0x74, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x5c, +}; + +char iris_mipi_rx_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x38, 0x02, 0x04, 0xf0, 0x00, 0x00, 0x77, 0x00, 0x00, 0x03, 0x04, 0xf0, + 0x00, 0x00, 0xdf, 0x01, 0x04, 0x03, 0x04, 0xf0, 0x00, 0x00, 0x55, 0x03, 0x04, 0x18, 0x04, 0xf0, + 0x80, 0x07, 0x00, 0x00, 0x04, 0x01, 0x04, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x04, 0xf0, + 0xf0, 0x00, 0x10, 0x00, 0x48, 0x01, 0x04, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0xf0, + 0x00, 0x00, 0x00, 0x00, +}; + +char iris_mipi_tx_phy_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x02, 0xd0, 0xf0, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd0, 0xf0, + 0x04, 0x03, 0x41, 0x00, 0x1c, 0x00, 0xd0, 0xf0, 0x0c, 0x00, 0x00, 0x00, +}; + +char iris_mipi_tx_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x50, 0x00, 0xc0, 0xf0, 0x06, 0x00, 0x03, 0x3c, 0x54, 0x00, 0xc0, 0xf0, + 0x08, 0x24, 0x09, 0x24, 0x58, 0x00, 0xc0, 0xf0, 0x08, 0x20, 0x09, 0x24, 0x04, 0x00, 0xc0, 0xf0, + 0x01, 0x02, 0x00, 0x00, 0x18, 0x00, 0xc0, 0xf0, 0x02, 0x01, 0x4e, 0x03, 0x24, 0x00, 0xc0, 0xf0, + 0xff, 0x2f, 0x75, 0x00, 0x28, 0x00, 0xc0, 0xf0, 0x17, 0xff, 0xff, 0x00, 0x2c, 0x00, 0xc0, 0xf0, + 0x80, 0x07, 0x8c, 0x0a, 0x30, 0x00, 0xc0, 0xf0, 0xc4, 0x60, 0x01, 0x00, 0x44, 0x00, 0xc0, 0xf0, + 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc0, 0xf0, 0x1c, 0x02, 0x10, 0x00, 0x14, 0x00, 0xc0, 0xf0, + 0x1c, 0x02, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xf0, 0x11, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0xf0, + 0x38, 0x04, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0x39, 0xc1, 0x01, 0x02, +}; + +char iris_mipi_tx_te_dly_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x18, 0x00, 0xc0, 0xf0, 0x02, 0x01, 0x4e, 0x03, +}; + +char iris_dtg_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x20, 0xf0, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0xf0, + 0x46, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0xf0, 0x38, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x20, 0xf0, + 0x78, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x20, 0xf0, + 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x20, 0xf0, 0x80, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x20, 0xf0, + 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0xf0, 0x2b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x20, 0xf0, + 0x01, 0x0f, 0x00, 0x00, 0x28, 0x00, 0x20, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x20, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x20, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf0, + 0x01, 0x00, 0x00, 0x00, +}; + +char iris_dtg_te_dly_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x28, 0x00, 0x20, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x20, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf0, 0x01, 0x00, 0x00, 0x00, +}; + +char iris_dport_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x22, 0xf0, 0x07, 0x80, 0x00, 0xe0, 0x04, 0x00, 0x22, 0xf0, + 0x03, 0x08, 0x00, 0x21, 0x08, 0x00, 0x22, 0xf0, 0x38, 0x04, 0x80, 0x47, 0x0c, 0x00, 0x22, 0xf0, + 0x00, 0x08, 0x00, 0x06, 0x10, 0x00, 0x22, 0xf0, 0x02, 0x18, 0x08, 0x06, 0x14, 0x00, 0x22, 0xf0, + 0x00, 0x01, 0x04, 0x00, 0x28, 0x00, 0x22, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x22, 0xf0, + 0x01, 0x00, 0x00, 0x00, +}; + +char iris_scaler_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0xa2, 0xf0, 0x60, 0x66, 0x00, 0x00, 0x04, 0x00, 0xa2, 0xf0, + 0x41, 0x04, 0x00, 0x00, 0x08, 0x00, 0xa2, 0xf0, 0xee, 0x8e, 0x03, 0x00, 0x0c, 0x00, 0xa2, 0xf0, + 0xee, 0x8e, 0x03, 0x00, 0x10, 0x00, 0xa2, 0xf0, 0x00, 0x64, 0x00, 0x00, 0x14, 0x00, 0xa2, 0xf0, + 0x80, 0x07, 0x80, 0x07, 0x18, 0x00, 0xa2, 0xf0, 0x03, 0x00, 0x06, 0x00, 0x1c, 0x00, 0xa2, 0xf0, + 0x03, 0x00, 0x06, 0x00, 0x20, 0x00, 0xa2, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xa2, 0xf0, + 0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0xa2, 0xf0, 0x38, 0x04, 0x38, 0x04, 0x2c, 0x00, 0xa2, 0xf0, + 0x38, 0x8e, 0x03, 0x00, 0x30, 0x00, 0xa2, 0xf0, 0x38, 0x8e, 0x03, 0x00, 0x34, 0x00, 0xa2, 0xf0, + 0x03, 0x00, 0x06, 0x00, 0x38, 0x00, 0xa2, 0xf0, 0x03, 0x00, 0x06, 0x00, 0x3c, 0x00, 0xa2, 0xf0, + 0x0a, 0x64, 0x00, 0x00, 0x40, 0x00, 0xa2, 0xf0, 0x00, 0x00, 0x00, 0x00, +}; + +char iris_pwil_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x24, 0xf0, 0x94, 0x02, 0xa0, 0x00, 0x04, 0x00, 0x24, 0xf0, + 0x3e, 0x00, 0x40, 0x00, 0x08, 0x00, 0x24, 0xf0, 0x38, 0x04, 0x80, 0x07, 0x0c, 0x00, 0x24, 0xf0, + 0xf0, 0x00, 0xf0, 0x00, 0x10, 0x00, 0x24, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x14, 0x00, 0x24, 0xf0, + 0xe0, 0x01, 0x56, 0x03, 0x18, 0x00, 0x24, 0xf0, 0x10, 0x00, 0x10, 0xe4, 0x1c, 0x00, 0x24, 0xf0, + 0xaa, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x24, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x24, 0xf0, + 0xe0, 0x01, 0x56, 0x03, 0x28, 0x00, 0x24, 0xf0, 0xe0, 0x01, 0x56, 0x03, 0x2c, 0x00, 0x24, 0xf0, + 0xe0, 0x01, 0x56, 0x03, +}; + +char iris_pwil_timeout_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x84, 0x00, 0x24, 0xf0, 0xff, 0xff, 0xff, 0xff, +}; + +char iris_pwil_ctrl_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x40, 0x01, 0x24, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x24, 0xf0, + 0x00, 0x00, 0x55, 0x03, 0x48, 0x01, 0x24, 0xf0, 0x00, 0x00, 0xdf, 0x01, +}; + +char iris_pwil_update_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x4c, 0x01, 0x24, 0xf0, 0x01, 0x00, 0x00, 0x00, +}; + +char iris_dsc_dec_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, +}; + +char iris_dsc_dec_pps_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x68, 0xf0, + 0x00, 0x00, 0x00, 0x00, +}; +char iris_dsc_dec_update_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0xff, 0x69, 0xf0, 0x01, 0x00, 0x00, 0x00, +}; + +char iris_dsc_enc_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x00, 0x00, 0x60, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x60, 0xf0, + 0x02, 0x00, 0x00, 0x00, +}; + +char iris_dsc_enc_pps_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x64, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, +}; + +char iris_dsc_enc_init_0_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x08, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x60, 0xf0, + 0x00, 0x00, 0x00, 0x00, +}; + +char iris_dsc_enc_update_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x01, 0x60, 0xf0, 0x04, 0x00, 0x00, 0x00, +}; + +char iris_dpp_init_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x58, 0xf0, 0x1c, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x58, 0xf0, + 0x02, 0x00, 0x00, 0x00, +}; + +char panel_cmds0_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x05, 0x29, 0x00, 0x03, +}; +char panel_cmds1_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x05, 0x11, 0x00, 0x03, +}; +char panel_cmds2_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0x35, 0x00, 0x03, +}; +char panel_cmds3_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0x53, 0x20, 0x03, +}; +char panel_cmds4_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x29, 0x03, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, + 0xfc, 0x5a, 0x5a, 0x00, +}; +char panel_cmds5_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0xb0, 0x1e, 0x03, +}; +char panel_cmds6_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0xfd, 0x9e, 0x03, +}; +char panel_cmds7_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0xb0, 0x10, 0x03, +}; +char panel_cmds8_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0xb6, 0x54, 0x03, +}; +char panel_cmds9_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x29, 0x03, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, + 0xfc, 0xa5, 0xa5, 0x00, +}; +char panel_cmds10_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x29, 0x02, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, + 0x51, 0xff, 0x00, 0x00, +}; +char panel_cmds11_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0x3a, 0x77, 0x03, +}; +char panel_cmds12_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x15, 0x35, 0x00, 0x03, +}; +char panel_cmds13_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x39, 0x05, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, + 0x2a, 0x00, 0x00, 0x04, 0x14, 0xc0, 0xc1, 0xf0, 0x37, 0x00, 0x00, 0x00, +}; + +char panel_cmds14_payload[] = { + 0xf4, 0xff, 0xff, 0xff, 0x10, 0xc0, 0xc1, 0xf0, 0x39, 0x05, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, + 0x2b, 0x00, 0x00, 0x07, 0x14, 0xc0, 0xc1, 0xf0, 0x7f, 0x00, 0x00, 0x00, +}; + +struct dsi_cmd_desc iris_lightup_cmds[] = { + //mipi rx phy + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_mipi_rx_phy_cmds_payload)/sizeof(char), iris_mipi_rx_phy_cmds_payload, 0, NULL}, 1, 0x11}, + //sys + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds0_payload)/sizeof(char), iris_sys_cmds0_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds1_payload)/sizeof(char), iris_sys_cmds1_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds2_payload)/sizeof(char), iris_sys_cmds2_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds3_payload)/sizeof(char), iris_sys_cmds3_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds4_payload)/sizeof(char), iris_sys_cmds4_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds5_payload)/sizeof(char), iris_sys_cmds5_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_cmds6_payload)/sizeof(char), iris_sys_cmds6_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_misc_payload)/sizeof(char), iris_sys_misc_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_sys_te_dly_payload)/sizeof(char), iris_sys_te_dly_payload, 0, NULL}, 1, 0x11}, + //mipi rx + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_mipi_rx_payload)/sizeof(char), iris_mipi_rx_payload, 0, NULL}, 1, 0x11}, + //mipi tx + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_mipi_tx_phy_payload)/sizeof(char), iris_mipi_tx_phy_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_mipi_tx_payload)/sizeof(char), iris_mipi_tx_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_mipi_tx_te_dly_payload)/sizeof(char), iris_mipi_tx_te_dly_payload, 0, NULL}, 1, 0x11}, + //dtg + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dtg_init_payload), iris_dtg_init_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dtg_te_dly_payload), iris_dtg_te_dly_payload, 0, NULL}, 1, 0x11}, + //dport + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dport_init_payload), iris_dport_init_payload, 0, NULL}, 1, 0x11}, + //scaler 1d + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_scaler_init_payload), iris_scaler_init_payload, 0, NULL}, 1, 0x11}, + //pwil + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_pwil_init_payload), iris_pwil_init_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_pwil_timeout_payload), iris_pwil_timeout_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_pwil_ctrl_payload), iris_pwil_ctrl_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_pwil_update_payload), iris_pwil_update_payload, 0, NULL}, 1, 0x11}, + //dsc_decoder + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_dec_init_payload), iris_dsc_dec_init_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_dec_pps_payload), iris_dsc_dec_pps_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_dec_update_payload), iris_dsc_dec_update_payload, 0, NULL}, 1, 0x11}, + //dsc encoder + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_enc_init_payload), iris_dsc_enc_init_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_enc_pps_payload), iris_dsc_enc_pps_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_enc_init_0_payload), iris_dsc_enc_init_0_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dsc_enc_update_payload), iris_dsc_enc_update_payload, 0, NULL}, 1, 0x11}, + //dpp + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_dpp_init_payload), iris_dpp_init_payload, 0, NULL}, 1, 0x11}, + //panel command + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds0_payload), panel_cmds0_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds1_payload), panel_cmds1_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds2_payload), panel_cmds2_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds3_payload), panel_cmds3_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds4_payload), panel_cmds4_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds5_payload), panel_cmds5_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds6_payload), panel_cmds6_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds7_payload), panel_cmds7_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds8_payload), panel_cmds8_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds9_payload), panel_cmds9_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds10_payload), panel_cmds10_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds11_payload), panel_cmds11_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds12_payload), panel_cmds12_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds13_payload), panel_cmds13_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(panel_cmds14_payload), panel_cmds14_payload, 0, NULL}, 1, 0x11}, +}; + +char link_state_array[] = { + //mipi rx phy + 0, + //sys + 0, 0, 0, 0, 0, 0, 0, 0, 0, + //mipi rx + 0, + //mipi tx + 0, 0, 0, + //dtg + 0, 0, + //dport + 0, + //scaler1d + 0, + //pwil + 0, 0, 0, 0, + //dsc_decoder + 0, 0, 0, + //dsc encoder + 0, 0, 0, 0, + //dpp + 0, + //panel command + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +struct dsi_cmd_desc iris_lightoff_cmds[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_panel_off_cmds0_payload)/sizeof(char), iris_panel_off_cmds0_payload, 0, NULL}, 1, 0x11}, + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, sizeof(iris_panel_off_cmds1_payload)/sizeof(char), iris_panel_off_cmds1_payload, 0, NULL}, 1, 0x11}, +}; + + +char lightoff_link_state_array[] = { + 1, 1, +}; + + + +static struct dsi_panel_cmd_set iris_panel_cmds; +static struct dsi_panel_cmd_set iris_panel_off_cmds; + +int iris_init_cmds(void) +{ + int ls_arr_cnt = 0; + int cmds_arr_cnt = 0; + + ls_arr_cnt = ARRAY_SIZE(link_state_array); + cmds_arr_cnt = ARRAY_SIZE(iris_lightup_cmds); + if (ls_arr_cnt != cmds_arr_cnt) { + pr_err("the cmds_arr_cnt %0x != ls_arr_cnt %0x\n", cmds_arr_cnt, ls_arr_cnt); + return -EINVAL; + } + + iris_panel_cmds.cmds = iris_lightup_cmds; + iris_panel_cmds.count = cmds_arr_cnt; + + ls_arr_cnt = ARRAY_SIZE(iris_lightoff_cmds); + cmds_arr_cnt = ARRAY_SIZE(lightoff_link_state_array); + if (ls_arr_cnt != cmds_arr_cnt) { + pr_err("lightoff the cmds_arr_cnt %0x != ls_arr_cnt %0x\n", cmds_arr_cnt, ls_arr_cnt); + return -EINVAL; + } + iris_panel_off_cmds.cmds = iris_lightoff_cmds; + iris_panel_off_cmds.count = cmds_arr_cnt; + + return 0; +} + +void iris_get_cmds(struct dsi_panel_cmd_set *cmds, char **ls_arr) +{ + cmds->cmds = iris_panel_cmds.cmds; + cmds->count = iris_panel_cmds.count; + *ls_arr = link_state_array; +} + +void iris_get_lightoff_cmds(struct dsi_panel_cmd_set *cmds, char **ls_arr) +{ + cmds->cmds = iris_panel_off_cmds.cmds; + cmds->count = iris_panel_off_cmds.count; + *ls_arr = lightoff_link_state_array; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_dbg.c b/techpack/display/msm/dsi/iris/dsi_iris5_dbg.c new file mode 100755 index 000000000000..adac6e008481 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_dbg.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_ioctl.h" +#include "dsi_iris5_lut.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_log.h" + +#define IRIS_DBG_TOP_DIR "iris" +#define IRIS_DBG_FUNCSTATUS_FILE "iris_func_status" + +int iris_dbg_fstatus_open(struct inode *inode, struct file *file) +{ + if (inode->i_private) + file->private_data = inode->i_private; + return 0; +} + +/** + * read module's status + */ +static ssize_t iris_dbg_fstatus_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char *kbuf = NULL; + int size = count < PAGE_SIZE ? PAGE_SIZE : (int)count; + int len = 0; + struct iris_setting_info *iris_setting = iris_get_setting(); + struct quality_setting *pqlt_cur_setting = &iris_setting->quality_cur; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_cfg *pcfg1 = iris_get_cfg_by_index(DSI_PRIMARY); + + if (*ppos) + return 0; + + kbuf = vzalloc(size); + if (kbuf == NULL) { + IRIS_LOGE("Fatal erorr: No mem!\n"); + return -ENOMEM; + } + + len += snprintf(kbuf, size, + "iris function parameter info\n" + "***peaking_setting***\n" + "%-20s:\t%d\n", + "peaking", pqlt_cur_setting->pq_setting.peaking); + + len += snprintf(kbuf+len, size - len, + "***system_brightness***\n" + "%-20s:\t%d\n", + "system_brightness", + pqlt_cur_setting->system_brightness); + + len += snprintf(kbuf+len, size - len, + "***dspp_dirty***\n" + "%-20s:\t%d\n", + "dspp_dirty", pqlt_cur_setting->dspp_dirty); + + len += snprintf(kbuf+len, size - len, + "***dbc_setting***\n" + "%-20s:\t%d\n", + "dbc", pqlt_cur_setting->pq_setting.dbc); + + len += snprintf(kbuf+len, size - len, + "***lce_setting***\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n", + "mode", pqlt_cur_setting->pq_setting.lcemode, + "level", pqlt_cur_setting->pq_setting.lcelevel, + "graphics_detection", + pqlt_cur_setting->pq_setting.graphicdet); + + len += snprintf(kbuf+len, size - len, + "***cm_setting***\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n", + "cm6axis", pqlt_cur_setting->pq_setting.cm6axis, + "cmftc", pqlt_cur_setting->cmftc, + "cmcolortempmode", + pqlt_cur_setting->pq_setting.cmcolortempmode, + "colortempvalue", pqlt_cur_setting->colortempvalue, + "min_colortempvalue", + pqlt_cur_setting->min_colortempvalue, + "max_colortempvalue", + pqlt_cur_setting->max_colortempvalue, + "cmcolorgamut", + pqlt_cur_setting->pq_setting.cmcolorgamut, + "demomode", pqlt_cur_setting->pq_setting.demomode, + "source_switch", pqlt_cur_setting->source_switch); + + len += snprintf(kbuf+len, size - len, + "***lux_value***\n" + "%-20s:\t%d\n", + "luxvalue", pqlt_cur_setting->luxvalue); + + len += snprintf(kbuf+len, size - len, + "***cct_value***\n" + "%-20s:\t%d\n", + "cctvalue", pqlt_cur_setting->cctvalue); + + len += snprintf(kbuf+len, size - len, + "***reading_mode***\n" + "%-20s:\t%d\n", + "readingmode", pqlt_cur_setting->pq_setting.readingmode); + + len += snprintf(kbuf+len, size - len, + "***ambient_lut***\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n", + "al_en", pqlt_cur_setting->pq_setting.alenable, + "al_luxvalue", pqlt_cur_setting->luxvalue, + "al_bl_ratio", pqlt_cur_setting->al_bl_ratio); + + len += snprintf(kbuf+len, size - len, + "***sdr2hdr***\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n", + "sdr2hdr", pqlt_cur_setting->pq_setting.sdr2hdr, + "maxcll", pqlt_cur_setting->maxcll); + + len += snprintf(kbuf+len, size - len, + "***frc_setting***\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n" + "%-20s:\t%d\n", + "memc_level", pcfg1->frc_setting.memc_level, + "memc_osd", pcfg1->frc_setting.memc_osd, + "in_fps", pcfg->frc_setting.in_fps, + "out_fps", pcfg->frc_setting.out_fps, + "in_fps_configured", pcfg->frc_setting.in_fps_configured, + "low_latency", pcfg->frc_low_latency); + + len += snprintf(kbuf+len, size - len, + "***osd***\n" + "%-20s:\t%d\n", + "osd_en", pcfg->osd_enable); + + len += snprintf(kbuf+len, size - len, + "***analog_abypass***\n" + "%-20s:\t%d\n", + "abyp_mode", pcfg->abypss_ctrl.abypass_mode); + + len += snprintf(kbuf+len, size - len, + "***n2m***\n" + "%-20s:\t%d\n", + "n2m_en", pcfg1->n2m_enable); + + len += snprintf(kbuf+len, size - len, + "***osd protect window***\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n" + "%-20s:\t0x%x\n", + "osd0_tl", pcfg1->frc_setting.iris_osd0_tl, + "osd0_br", pcfg1->frc_setting.iris_osd0_br, + "osd1_tl", pcfg1->frc_setting.iris_osd1_tl, + "osd1_br", pcfg1->frc_setting.iris_osd1_br, + "osd2_tl", pcfg1->frc_setting.iris_osd2_tl, + "osd2_br", pcfg1->frc_setting.iris_osd2_br, + "osd3_tl", pcfg1->frc_setting.iris_osd3_tl, + "osd3_br", pcfg1->frc_setting.iris_osd3_br, + "osd4_tl", pcfg1->frc_setting.iris_osd4_tl, + "osd4_br", pcfg1->frc_setting.iris_osd4_br, + "osd_win_ctrl", pcfg1->frc_setting.iris_osd_window_ctrl, + "osd_win_ctrl", pcfg1->frc_setting.iris_osd_win_dynCompensate); + + len += snprintf(kbuf+len, size - len, + "***firmware_version***\n" + "%-20s:\t%d\n" //CID101064 + "%-20s:\t%d%d/%d/%d\n", + "version", pcfg1->app_version, + "date", pcfg1->app_date[3], pcfg1->app_date[2], pcfg1->app_date[1], pcfg1->app_date[0]); + + size = len; + if (len >= count) + size = count - 1; + + if (copy_to_user(ubuf, kbuf, size)) { + vfree(kbuf); + return -EFAULT; + } + + vfree(kbuf); + + *ppos += size; + + return size; +} + + +static const struct file_operations iris_dbg_fstatus_fops = { + .open = iris_dbg_fstatus_open, + .read = iris_dbg_fstatus_read, +}; + +void iris_display_mode_name_update(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg == NULL) + return; + + strlcpy(pcfg->display_mode_name, "Not Set", sizeof(pcfg->display_mode_name)); + + if (pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) { + strlcpy(pcfg->display_mode_name, "ABYPASS", sizeof(pcfg->display_mode_name)); + } else { + if (pcfg->osd_enable) { + if (pcfg->pwil_mode == FRC_MODE) + strncpy(pcfg->display_mode_name, "DUAL-MEMC", sizeof(pcfg->display_mode_name)); + else + strncpy(pcfg->display_mode_name, "DUAL-PT", sizeof(pcfg->display_mode_name)); + return; + } + strncpy(pcfg->display_mode_name, "PT", sizeof(pcfg->display_mode_name)); + if (pcfg->pwil_mode == FRC_MODE) { + strlcpy(pcfg->display_mode_name, "MEMC", sizeof(pcfg->display_mode_name)); + } else if (pcfg->pwil_mode == RFB_MODE) { + strlcpy(pcfg->display_mode_name, "RFB", sizeof(pcfg->display_mode_name)); + } + } +} + +static ssize_t iris_dbg_display_mode_show(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char *kbuf = NULL; + int size = count < PAGE_SIZE ? PAGE_SIZE : count; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (*ppos) + return 0; + + kbuf = vzalloc(size); + if (kbuf == NULL) { + IRIS_LOGE("Fatal erorr: No mem!\n"); + return -ENOMEM; + } + + iris_display_mode_name_update(); + + snprintf(kbuf, size, + "%s\n", pcfg->display_mode_name); + + size = strlen(kbuf); + if (size >= count) + size = count - 1; + + if (copy_to_user(ubuf, kbuf, size)) { + vfree(kbuf); + return -EFAULT; + } + + vfree(kbuf); + + *ppos += size; + + return size; +} + +static const struct file_operations iris_dbg_dislay_mode_fops = { + .open = simple_open, + .read = iris_dbg_display_mode_show, +}; + +int iris_dbgfs_status_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg = NULL; + + pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir(IRIS_DBG_TOP_DIR, NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("create dir for iris failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + if (debugfs_create_file(IRIS_DBG_FUNCSTATUS_FILE, 0644, + pcfg->dbg_root, display, + &iris_dbg_fstatus_fops) == NULL) + IRIS_LOGE("create file func_status failed\n"); + + if (debugfs_create_file("display_mode", 0644, + pcfg->dbg_root, display, + &iris_dbg_dislay_mode_fops) == NULL) + IRIS_LOGE("create file display_mode failed\n"); + + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_def.h b/techpack/display/msm/dsi/iris/dsi_iris5_def.h new file mode 100755 index 000000000000..9f87cc7963d0 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_def.h @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_DEF_H_ +#define _DSI_IRIS_DEF_H_ + + +// Use Iris Analog bypass mode to light up panel +// Note: input timing should be same with output timing +//#define IRIS_ABYP_LIGHTUP +//#define IRIS_MIPI_TEST +#define IRIS_CFG_NUM 2 + +#define IRIS_FIRMWARE_NAME "iris5.fw" +#define IRIS_CCF1_FIRMWARE_NAME "iris5_ccf1.fw" +#define IRIS_CCF2_FIRMWARE_NAME "iris5_ccf2.fw" +#define IRIS_CCF1_CALIBRATED_FIRMWARE_NAME "iris5_ccf1b.fw" +#define IRIS_CCF2_CALIBRATED_FIRMWARE_NAME "iris5_ccf2b.fw" +#define IRIS3_CHIP_VERSION 0x6933 +#define IRIS5_CHIP_VERSION 0x6935 + +#define DIRECT_BUS_HEADER_SIZE 8 + +#define LUT_LEN 256 +#define CM_LUT_GROUP 3 // table 0,3,6 should store at the same address in iris +#define SCALER1D_LUT_NUMBER 9 +#define SDR2HDR_LUT_BLOCK_SIZE (128*4) +#define SDR2HDR_LUT2_BLOCK_NUMBER (6) +#define SDR2HDR_LUTUVY_BLOCK_NUMBER (12) +#define SDR2HDR_LUT2_ADDRESS 0x3000 +#define SDR2HDR_LUTUVY_ADDRESS 0x6000 +#define SDR2HDR_LUT_BLOCK_ADDRESS_INC 0x400 +#define SDR2HDR_LUT2_BLOCK_CNT (6) //for ambient light lut +#define SDR2HDR_LUTUVY_BLOCK_CNT (12) // for maxcll lut + +#define PANEL_BL_MAX_RATIO 10000 +#define IRIS_MODE_RFB 0x0 +#define IRIS_MODE_FRC_PREPARE 0x1 +#define IRIS_MODE_FRC_PREPARE_DONE 0x2 +#define IRIS_MODE_FRC 0x3 +#define IRIS_MODE_FRC_CANCEL 0x4 +#define IRIS_MODE_FRC_PREPARE_RFB 0x5 +#define IRIS_MODE_FRC_PREPARE_TIMEOUT 0x6 +#define IRIS_MODE_RFB2FRC 0x7 +#define IRIS_MODE_RFB_PREPARE 0x8 +#define IRIS_MODE_RFB_PREPARE_DONE 0x9 +#define IRIS_MODE_RFB_PREPARE_TIMEOUT 0xa +#define IRIS_MODE_FRC2RFB 0xb +#define IRIS_MODE_PT_PREPARE 0xc +#define IRIS_MODE_PT_PREPARE_DONE 0xd +#define IRIS_MODE_PT_PREPARE_TIMEOUT 0xe +#define IRIS_MODE_RFB2PT 0xf +#define IRIS_MODE_PT2RFB 0x10 +#define IRIS_MODE_PT 0x11 +#define IRIS_MODE_KICKOFF60_ENABLE 0x12 +#define IRIS_MODE_KICKOFF60_DISABLE 0x13 +#define IRIS_MODE_PT2BYPASS 0x14 +#define IRIS_MODE_BYPASS 0x15 +#define IRIS_MODE_BYPASS2PT 0x16 +#define IRIS_MODE_PTLOW_PREPARE 0x17 +#define IRIS_MODE_DSI_SWITCH_2PT 0x18 // dsi mode switch during RFB->PT +#define IRIS_MODE_DSI_SWITCH_2RFB 0x19 // dsi mode switch during PT->RFB +#define IRIS_MODE_FRC_POST 0x1a // for set parameters after FRC +#define IRIS_MODE_RFB_PREPARE_DELAY 0x1b // for set parameters before RFB +#define IRIS_MODE_RFB_POST 0x1c // for set parameters after RFB +#define IRIS_MODE_INITING 0xff +#define IRIS_MODE_OFF 0xf0 +#define IRIS_MODE_HDR_EN 0x20 + +enum DBC_LEVEL { + DBC_INIT = 0, + DBC_OFF, + DBC_LOW, + DBC_MIDDLE, + DBC_HIGH, + CABC_DLV_OFF = 0xF1, + CABC_DLV_LOW, + CABC_DLV_MIDDLE, + CABC_DLV_HIGH, +}; + +enum SDR2HDR_LEVEL { + SDR2HDR_LEVEL0 = 0, + SDR2HDR_LEVEL1, + SDR2HDR_LEVEL2, + SDR2HDR_LEVEL3, + SDR2HDR_LEVEL4, + SDR2HDR_LEVEL5, + SDR2HDR_LEVEL_CNT +}; + +enum SDR2HDR_TABLE_TYPE { + SDR2HDR_LUT0 = 0, + SDR2HDR_LUT1, + SDR2HDR_LUT2, + SDR2HDR_LUT3, + SDR2HDR_UVY0, + SDR2HDR_UVY1, + SDR2HDR_UVY2, + SDR2HDR_INV_UV0, + SDR2HDR_INV_UV1, +}; + +enum FRC_PHASE_TYPE { + FRC_PHASE_V1_128 = 0, + FRC_PHASE_V2_12TO60_25, + FRC_PHASE_V2_12TO90_75, + FRC_PHASE_V2_12TO120_50, + FRC_PHASE_V2_15TO60_20, + FRC_PHASE_V2_15TO90_30, + FRC_PHASE_V2_15TO120_40, + FRC_PHASE_V2_24TO60_25, + FRC_PHASE_V2_24TO90_75, + FRC_PHASE_V2_24TO120_50, + FRC_PHASE_V2_25TO60_60, + FRC_PHASE_V2_25TO90_90, + FRC_PHASE_V2_25TO120_120, + FRC_PHASE_V2_30TO60_20, + FRC_PHASE_V2_30TO90_30, + FRC_PHASE_V2_30TO120_40, + FRC_PHASE_V2_60TO90_15, + FRC_PHASE_V2_60TO120_20, + FRC_PHASE_TYPE_CNT +}; + +enum { + IRIS_CONT_SPLASH_LK = 1, + IRIS_CONT_SPLASH_KERNEL, + IRIS_CONT_SPLASH_NONE, + IRIS_CONT_SPLASH_BYPASS, + IRIS_CONT_SPLASH_BYPASS_PRELOAD, +}; + +enum { + IRIS_DTSI0_PIP_IDX = 0, + IRIS_DTSI1_PIP_IDX, + IRIS_LUT_PIP_IDX, + IRIS_PIP_IDX_CNT, + + IRIS_DTSI_NONE = 0xFF, +}; + +enum { + IRIS_IP_START = 0x00, + IRIS_IP_SYS = IRIS_IP_START, + IRIS_IP_RX = 0x01, + IRIS_IP_TX = 0x02, + IRIS_IP_PWIL = 0x03, + IRIS_IP_DPORT = 0x04, + IRIS_IP_DTG = 0x05, + IRIS_IP_PWM = 0x06, + IRIS_IP_DSC_DEN = 0x07, + IRIS_IP_DSC_ENC = 0x08, + IRIS_IP_SDR2HDR = 0x09, + IRIS_IP_CM = 0x0a, + IRIS_IP_SCALER1D = 0x0b, + IRIS_IP_PEAKING = 0x0c, + IRIS_IP_LCE = 0x0d, + IRIS_IP_DPP = 0x0e, + IRIS_IP_DBC = 0x0f, + IRIS_IP_EXT = 0x10, + IRIS_IP_DMA = 0x11, + + IRIS_IP_RX_2 = 0x021, + IRIS_IP_SRAM = 0x022, + IRIS_IP_PWIL_2 = 0x023, + IRIS_IP_DSC_ENC_2 = 0x24, + IRIS_IP_DSC_DEN_2 = 0x25, + IRIS_IP_PBSEL_1 = 0x26, + IRIS_IP_PBSEL_2 = 0x27, + IRIS_IP_PBSEL_3 = 0x28, + IRIS_IP_PBSEL_4 = 0x29, + IRIS_IP_OSD_COMP = 0x2a, + IRIS_IP_OSD_DECOMP = 0x2b, + IRIS_IP_OSD_BW = 0x2c, + IRIS_IP_PSR_MIF = 0x2d, + IRIS_IP_BLEND = 0x2e, + IRIS_IP_SCALER1D_2 = 0x2f, + IRIS_IP_FRC_MIF = 0x30, + IRIS_IP_FRC_DS = 0x31, + IRIS_IP_GMD = 0x32, + IRIS_IP_FBD = 0x33, + IRIS_IP_CADDET = 0x34, + IRIS_IP_MVC = 0x35, + IRIS_IP_FI = 0x36, + IRIS_IP_DSC_DEC_AUX = 0x37, + + IRIS_IP_END, + IRIS_IP_CNT = IRIS_IP_END +}; + +enum LUT_TYPE { + LUT_IP_START = 128, /*0x80*/ + DBC_LUT = LUT_IP_START, + CM_LUT, + SDR2HDR_LUT, + SCALER1D_LUT, + AMBINET_HDR_GAIN, /*HDR case*/ + AMBINET_SDR2HDR_LUT, /*SDR2HDR case;*/ + GAMMA_LUT, + FRC_PHASE_LUT, + APP_CODE_LUT, + DPP_DITHER_LUT, + SCALER1D_PP_LUT, + DTG_PHASE_LUT, + APP_VERSION_LUT, + LUT_IP_END +}; + +enum FIRMWARE_STATUS { + FIRMWARE_LOAD_FAIL, + FIRMWARE_LOAD_SUCCESS, + FIRMWARE_IN_USING, +}; + +enum result { + IRIS_FAILED = -1, + IRIS_SUCCESS = 0, +}; + +enum PANEL_TYPE { + PANEL_LCD_SRGB = 0, + PANEL_LCD_P3, + PANEL_OLED, +}; + +enum LUT_MODE { + INTERPOLATION_MODE = 0, + SINGLE_MODE, +}; + +enum SCALER_IP_TYPE { + SCALER_INPUT = 0, + SCALER_PP, +}; + +struct iris_pq_setting { + u32 peaking:4; + u32 cm6axis:2; + u32 cmcolortempmode:2; + u32 cmcolorgamut:4; + u32 lcemode:2; + u32 lcelevel:3; + u32 graphicdet:1; + u32 alenable:1; + u32 dbc:2; + u32 demomode:3; + u32 sdr2hdr:4; + u32 readingmode:4; +}; + +struct quality_setting { + struct iris_pq_setting pq_setting; + u32 cctvalue; + u32 colortempvalue; + u32 luxvalue; + u32 maxcll; + u32 source_switch; + u32 al_bl_ratio; + u32 system_brightness; + u32 min_colortempvalue; + u32 max_colortempvalue; + u32 dspp_dirty; + u32 scurvelevel; + u32 cmftc; +}; + +struct iris_setting_info { + struct quality_setting quality_cur; + struct quality_setting quality_def; +}; +struct ocp_header { + u32 header; + u32 address; +}; + +struct iris_update_ipopt { + uint8_t ip; + uint8_t opt_old; + uint8_t opt_new; + uint8_t skip_last; +}; + +struct iris_update_regval { + uint8_t ip; + uint8_t opt_id; + uint16_t reserved; + uint32_t mask; + //uint32_t addr; + uint32_t value; +}; + +struct iris_lp_ctrl { + bool dynamic_power; + bool ulps_lp; + bool abyp_enable; + bool esd_enable; + int esd_cnt; +}; + +struct iris_abypass_ctrl { + bool analog_bypass_disable; + uint8_t abypass_mode; + uint16_t pending_mode; // pending_mode is accessed by SDEEncoder and HWBinder + int abyp_switch_state; + int frame_delay; + struct mutex abypass_mutex; +}; + +struct iris_frc_setting { + u8 memc_level; + u8 mv_buf_num; + u8 in_fps; + u8 out_fps; + u16 disp_hres; + u16 disp_vres; + u16 input_vtotal; + u16 disp_htotal; + u16 disp_vtotal; + uint32_t memc_hres; + uint32_t memc_vres; + uint32_t memc_dsc_bpp; + u32 video_baseaddr; + u32 mv_baseaddr; + u8 v2_lut_index; + u8 v2_phaselux_idx_max; + u32 v2_period_phasenum; + u8 in_fps_configured; + u8 default_out_fps; + u8 memc_osd; + u32 frcc_pref_ctrl; + uint32_t iris_osd0_tl; + uint32_t iris_osd1_tl; + uint32_t iris_osd2_tl; + uint32_t iris_osd3_tl; + uint32_t iris_osd4_tl; + uint32_t iris_osd0_br; + uint32_t iris_osd1_br; + uint32_t iris_osd2_br; + uint32_t iris_osd3_br; + uint32_t iris_osd4_br; + uint32_t iris_osd_window_ctrl; + uint32_t iris_osd_win_dynCompensate; + uint32_t short_video; +}; + +struct iris_mspwil_parameter { + int frc_var_disp; // -1: mean no update + int frc_pt_switch_on; // -1: mean no update + int cmd_disp_on; // -1: mean no update + int ratio_update; + int out_fps_ratio; + int in_fps_ratio; + int mvc_01phase_update; + int mvc_01phase; +}; + +enum pwil_mode { + PT_MODE, + RFB_MODE, + FRC_MODE, +}; + +enum iris_config_type { + IRIS_PEAKING = 0, + IRIS_MEMC_LEVEL = 5, + USER_DEMO_WND = 17, + IRIS_CHIP_VERSION = 33, // 0x0 : IRIS2, 0x1 : IRIS2-plus, 0x2 : IRIS3-lite + IRIS_LUX_VALUE = 34, + IRIS_CCT_VALUE = 35, + IRIS_READING_MODE = 36, + + IRIS_CM_6AXES = 37, + IRIS_CM_FTC_ENABLE = 38, + IRIS_CM_COLOR_TEMP_MODE = 39, + IRIS_CM_COLOR_GAMUT = 40, + IRIS_LCE_MODE = 41, + IRIS_LCE_LEVEL = 42, + IRIS_GRAPHIC_DET_ENABLE = 43, + IRIS_AL_ENABLE = 44, //AL means ambient light + IRIS_DBC_LEVEL = 45, + IRIS_DEMO_MODE = 46, + IRIS_SDR2HDR = 47, + IRIS_COLOR_TEMP_VALUE = 48, + IRIS_HDR_MAXCLL = 49, + IRIS_CM_COLOR_GAMUT_PRE = 51, + IRIS_DBC_LCE_POWER = 52, + IRIS_DBC_LCE_DATA_PATH = 53, + IRIS_DYNAMIC_POWER_CTRL = 54, + IRIS_DMA_LOAD = 55, + IRIS_ANALOG_BYPASS_MODE = 56, + IRIS_PANEL_TYPE = 57, + IRIS_HDR_PANEL_NITES_SET = 60, + IRIS_PEAKING_IDLE_CLK_ENABLE = 61, + IRIS_CM_MAGENTA_GAIN = 62, + IRIS_CM_RED_GAIN = 63, + IRIS_CM_YELLOW_GAIN = 64, + IRIS_CM_GREEN_GAIN = 65, + IRIS_CM_BLUE_GAIN = 66, + IRIS_CM_CYAN_GAIN = 67, + IRIS_BLC_PWM_ENABLE = 68, + IRIS_DBC_LED_GAIN = 69, + IRIS_SCALER_FILTER_LEVEL = 70, + IRIS_CCF1_UPDATE = 71, + IRIS_CCF2_UPDATE = 72, + IRIS_FW_UPDATE = 73, + IRIS_HUE_SAT_ADJ = 74, + IRIS_SCALER_PP_FILTER_LEVEL = 76, + IRIS_CSC_MATRIX = 75, + IRIS_CONTRAST_DIMMING = 80, + IRIS_S_CURVE = 81, + IRIS_BRIGHTNESS_CHIP = 82, + IRIS_HDR_PREPARE = 90, + IRIS_HDR_COMPLETE = 91, + IRIS_MCF_DATA = 92, + IRIS_Y5P = 93, + IRIS_PANEL_NITS = 99, + + IRIS_DBG_TARGET_REGADDR_VALUE_GET = 103, + IRIS_DBG_TARGET_REGADDR_VALUE_SET = 105, + IRIS_DBG_KERNEL_LOG_LEVEL = 106, + IRIS_DBG_SEND_PACKAGE = 107, + IRIS_DBG_LOOP_BACK_MODE = 108, + IRIS_DBG_LOOP_BACK_MODE_RES = 109, + IRIS_DBG_TARGET_REGADDR_VALUE_SET2 = 112, + IRIS_DEBUG_CAP = 113, + + IRIS_MODE_SET = 120, + IRIS_VIDEO_FRAME_RATE_SET = 121, + IRIS_OUT_FRAME_RATE_SET = 122, // debug only + IRIS_OSD_ENABLE = 123, + IRIS_OSD_AUTOREFRESH = 124, + IRIS_OSD_OVERFLOW_ST = 125, + // [23-16]: pwil mode, [15-8]: tx mode, [7-0]: rx mode + IRIS_WORK_MODE = 126, + IRIS_FRC_LOW_LATENCY = 127, + IRIS_PANEL_TE = 128, + IRIS_AP_TE = 129, + IRIS_N2M_ENABLE = 130, + IRIS_WAIT_VSYNC = 132, + IRIS_MIPI2RX_PWRST = 133, + IRIS_DUAL2SINGLE_ST = 134, + IRIS_MEMC_OSD = 135, + IRIS_MEMC_OSD_PROTECT = 136, + IRIS_LCE_DEMO_WINDOW = 137, + IRIS_CM_PARA_SET = 138, + IRIS_PARAM_VALID = 144, + IRIS_CONFIG_TYPE_MAX +}; + +enum SDR2HDR_CASE { + SDR2HDR_Bypass = 0, + HDR10In_ICtCp, + HDR10In_YCbCr, + ICtCpIn_YCbCr, + SDR709_2_709, + SDR709_2_p3, + SDR709_2_2020, +}; + +enum SDR2HDR_LUT_GAMMA_INDEX { + SDR2HDR_LUT_GAMMA_120 = 0, + SDR2HDR_LUT_GAMMA_106 = 1, + SDR2HDR_LUT_GAMMA_102 = 2, + SDR2HDR_LUT_GAMMA_100 = 3, + SDR2HDR_LUT_GAMMA_MAX +}; + +enum iris_chip_version { + IRIS2_VER = 0, + IRIS2PLUS_VER, + IRIS3LITE_VER, + IRIS5_VER, + IRIS6_VER, + IRISSOFT_VER, + IRIS5DUAL_VER, + UNKOWN_VER +}; + +enum iris_abypass_status { + PASS_THROUGH_MODE = 0, + ANALOG_BYPASS_MODE, + ABP2PT_SWITCHING, + MAX_MODE = 255, +}; + +#endif // _DSI_IRIS_DEF_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_extended.c b/techpack/display/msm/dsi/iris/dsi_iris5_extended.c new file mode 100755 index 000000000000..8da06f225884 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_extended.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +#include <video/mipi_display.h> + +#include "dsi_display.h" +#include "dsi_panel.h" +#include "dsi_iris5_api.h" +#include "dsi_iris5.h" +#include "dsi_iris5_log.h" + + +static bool iris_chip_enable; +static bool soft_iris_enable; +static bool iris_dual_enable; + +void iris_query_capability(struct dsi_panel *panel) +{ + bool chip_enable = false; + bool soft_enable = false; + struct dsi_parser_utils *utils = NULL; + + if (!panel) + return; + + if (!strcmp(panel->type, "secondary")) { + IRIS_LOGI("%s(), sencondary panel: %s", __func__, panel->name); + iris_dual_enable = true; + return; + } + + utils = &panel->utils; + if (!utils) + return; + + chip_enable = utils->read_bool(utils->data, + "pxlw,iris-chip-enable"); + soft_enable = utils->read_bool(utils->data, + "pxlw,soft-iris-enable"); + + IRIS_LOGI("%s(), iris chip enable: %s, soft iris enable: %s", + __func__, + chip_enable ? "true" : "false", + soft_enable ? "true" : "false"); + iris_chip_enable = chip_enable; + soft_iris_enable = soft_enable; +} + +bool iris_is_chip_supported(void) +{ + return iris_chip_enable; +} + +bool iris_is_softiris_supported(void) +{ + return soft_iris_enable; +} + +bool iris_is_dual_supported(void) +{ + return iris_chip_enable && iris_dual_enable; +} + + +bool iris_is_pt_mode(struct dsi_panel *panel) +{ + return iris_get_abyp_mode(panel) == PASS_THROUGH_MODE; +} + +void iris_dsi_display_res_init(struct dsi_display *display) +{ + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return; + + IRIS_LOGI("%s(), display type: %s", __func__, display->display_type); + + if (iris_is_chip_supported()) { + if (NULL != display->display_type && !strcmp(display->display_type, "secondary")) { + display->panel->is_secondary = true; + iris_set_cfg_index(DSI_SECONDARY); + } else { + display->panel->is_secondary = false; + iris_set_cfg_index(DSI_PRIMARY); + } + + iris_parse_param(display); + } + iris_init(display, display->panel); +} + +static int panel_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 panel_debug_base_release(struct inode *inode, struct file *file) +{ + return 0; +} + +#define PANEL_REG_MAX_OFFSET 1024 // FIXME + +static ssize_t panel_debug_base_offset_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + u32 off, cnt; + char buf[64]; + + if (!display) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (sscanf(buf, "%x %u", &off, &cnt) != 2) + return -EINVAL; + + if (off > PANEL_REG_MAX_OFFSET) + return -EINVAL; + + if (cnt > (PANEL_REG_MAX_OFFSET - off)) + cnt = PANEL_REG_MAX_OFFSET - off; + + display->off = off; + display->cnt = cnt; + + pr_debug("offset=%x cnt=%d\n", off, cnt); + + return count; +} + +static ssize_t panel_debug_base_offset_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + int len; + char buf[64]; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), "0x%02x %x\n", display->off, display->cnt); + + if (len < 0 || len >= sizeof(buf)) + return -EINVAL; + + if (count < sizeof(buf)) + return -EINVAL; + if (copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + return len; +} + +/* Hex number + whitespace */ +#define NEXT_VALUE_OFFSET 3 + +#define PANEL_CMD_MIN_TX_COUNT 2 + + +extern int iris_dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, + bool *state); +static ssize_t panel_debug_base_reg_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char buf[64]; + char reg[64]; + u32 len = 0, value = 0; + char *bufp; + bool state = false; + int rc; + + struct dsi_cmd_desc cmds = { + { 0 }, // msg + 1, // last + 0 // wait + }; +#ifndef IRIS_ABYP_LIGHTUP + struct dsi_panel_cmd_set cmdset = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &cmds, + }; +#endif + + if (!display) + return -ENODEV; + + /* get command string from user */ + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + bufp = buf; + /* End of a hex value in given string */ + bufp[NEXT_VALUE_OFFSET - 1] = 0; + while (kstrtouint(bufp, 16, &value) == 0) { + reg[len++] = value; + if (len >= sizeof(reg)) { + pr_err("wrong input reg len\n"); + return -EINVAL; + } + bufp += NEXT_VALUE_OFFSET; + if ((bufp >= (buf + count)) || (bufp < buf)) { + pr_warn("%s,buffer out-of-bounds\n", __func__); + break; + } + /* End of a hex value in given string */ + if ((bufp + NEXT_VALUE_OFFSET - 1) < (buf + count)) + bufp[NEXT_VALUE_OFFSET - 1] = 0; + } + if (len < PANEL_CMD_MIN_TX_COUNT) { + pr_err("wrong input reg len\n"); + return -EINVAL; + } + + cmds.msg.type = display->cmd_data_type; + cmds.msg.flags = MIPI_DSI_MSG_LASTCOMMAND; + cmds.msg.tx_len = len; + cmds.msg.tx_buf = reg; + + rc = iris_dsi_display_ctrl_get_host_init_state(display, &state); + if (!rc && state) { + dsi_panel_acquire_panel_lock(display->panel); +#ifdef IRIS_ABYP_LIGHTUP + rc = display->host.ops->transfer(&display->host, &cmds.msg); +#else + iris_pt_send_panel_cmd(display->panel, &cmdset); +#endif + dsi_panel_release_panel_lock(display->panel); + } + + return rc ? rc : count; +} + +#define PANEL_REG_ADDR_LEN 8 +#define PANEL_REG_FORMAT_LEN 5 + +static ssize_t panel_debug_base_reg_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + u32 i, len = 0, reg_buf_len = 0; + char *panel_reg_buf, *rx_buf; + int rc; + bool state = false; + char panel_reg[2] = { 0 }; + struct dsi_cmd_desc cmds = { + { 0 }, // msg + 1, // last + 0 // wait + }; +#ifndef IRIS_ABYP_LIGHTUP + struct dsi_panel_cmd_set cmdset = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &cmds, + }; +#endif + + if (!display) + return -ENODEV; + if (!display->cnt) + return 0; + if (*ppos) + return 0; /* the end */ + + /* '0x' + 2 digit + blank = 5 bytes for each number */ + reg_buf_len = (display->cnt * PANEL_REG_FORMAT_LEN) + + PANEL_REG_ADDR_LEN + 1; + if (count < reg_buf_len) + return -EINVAL; + + rx_buf = kzalloc(display->cnt, GFP_KERNEL); + panel_reg_buf = kzalloc(reg_buf_len, GFP_KERNEL); + + if (!rx_buf || !panel_reg_buf) { + pr_err("not enough memory to hold panel reg dump\n"); + rc = -ENOMEM; + goto read_reg_fail; + } + + panel_reg[0] = display->off; + + cmds.msg.type = MIPI_DSI_DCS_READ; + cmds.msg.flags = MIPI_DSI_MSG_LASTCOMMAND | MIPI_DSI_MSG_REQ_ACK; + cmds.msg.tx_len = 2; + cmds.msg.tx_buf = panel_reg; + cmds.msg.rx_len = display->cnt; + cmds.msg.rx_buf = rx_buf; + + rc = iris_dsi_display_ctrl_get_host_init_state(display, &state); + if (!rc && state) { + dsi_panel_acquire_panel_lock(display->panel); +#ifdef IRIS_ABYP_LIGHTUP + rc = display->host.ops->transfer(&display->host, &cmds.msg); +#else + iris_pt_send_panel_cmd(display->panel, &cmdset); +#endif + dsi_panel_release_panel_lock(display->panel); + } + + if (rc) + goto read_reg_fail; + + len = scnprintf(panel_reg_buf, reg_buf_len, "0x%02x: ", display->off); + + for (i = 0; (len < reg_buf_len) && (i < display->cnt); i++) + len += scnprintf(panel_reg_buf + len, reg_buf_len - len, + "0x%02x ", rx_buf[i]); + + if (len) + panel_reg_buf[len - 1] = '\n'; + + if (copy_to_user(user_buf, panel_reg_buf, len)) { + rc = -EFAULT; + goto read_reg_fail; + } + + *ppos += len; /* increase offset */ + rc = len; + +read_reg_fail: + kfree(rx_buf); + kfree(panel_reg_buf); + return rc; +} + +static const struct file_operations panel_off_fops = { + .open = panel_debug_base_open, + .release = panel_debug_base_release, + .read = panel_debug_base_offset_read, + .write = panel_debug_base_offset_write, +}; + +static const struct file_operations panel_reg_fops = { + .open = panel_debug_base_open, + .release = panel_debug_base_release, + .read = panel_debug_base_reg_read, + .write = panel_debug_base_reg_write, +}; + +void iris_dsi_display_debugfs_init(struct dsi_display *display, + struct dentry *dir, struct dentry *dump_file) +{ + if (!iris_is_chip_supported()) + return; + + display->off = 0x0a; + display->cnt = 1; + display->cmd_data_type = MIPI_DSI_DCS_LONG_WRITE; + + dump_file = debugfs_create_x8("cmd_data_type", 0600, dir, &display->cmd_data_type); + if (IS_ERR_OR_NULL(dump_file)) + pr_err("[%s] debugfs create panel cmd_data_type file failed, rc=%ld\n", + display->name, PTR_ERR(dump_file)); + + dump_file = debugfs_create_file("off", + 0600, + dir, + display, + &panel_off_fops); + if (IS_ERR_OR_NULL(dump_file)) + pr_err("[%s] debugfs create panel off file failed, rc=%ld\n", + display->name, PTR_ERR(dump_file)); + + dump_file = debugfs_create_file("reg", + 0600, + dir, + display, + &panel_reg_fops); + if (IS_ERR_OR_NULL(dump_file)) + pr_err("[%s] debugfs create panel reg file failed, rc=%ld\n", + display->name, PTR_ERR(dump_file)); +} + +void iris_dsi_panel_dump_pps(struct dsi_panel_cmd_set *set) +{ + if (!iris_is_chip_supported()) + return; + + if (!set) + return; + + IRIS_LOGI("%s(), qcom pps table:", __func__); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, + set->cmds->msg.tx_buf, set->cmds->msg.tx_len, false); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 4, 10, + set->cmds->msg.tx_buf, set->cmds->msg.tx_len, false); +} + +bool iris_enable_dsi_cmd_log = false; + +void iris_dsi_ctrl_dump_desc_cmd(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; + + if (!iris_enable_dsi_cmd_log) + return; + + if (!iris_is_chip_supported()) + return; + + /* 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 ", (unsigned int)(msg->tx_len) >> 8, (unsigned int)(msg->tx_len) & 0x00FF);//CID101695 + + /* 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; + } + + IRIS_LOGI("%s(), %s", __func__, buf); +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_frc.c b/techpack/display/msm/dsi/iris/dsi_iris5_frc.c new file mode 100755 index 000000000000..010436dce10e --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_frc.c @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <linux/types.h> +#include <dsi_drm.h> +#include <sde_encoder_phys.h> +#include "dsi_display.h" +#include "dsi_panel.h" +#include "dsi_iris5.h" +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_log.h" + + +enum { + MIPI2_LP_PRE = 0, + MIPI2_LP_SWRST, + MIPI2_LP_POST, + MIPI2_LP_FINISH, + MIPI2_LP_INVALID, +}; + +struct osd_blending_st { + atomic_t compression_mode; + uint32_t enter_lp_st; +}; + +static int32_t iris_disable_osd_autorefresh; +static struct osd_blending_st osd_blending_work; + +static void __iris_update_vfr_work(struct work_struct *work) +{ + struct iris_cfg *pcfg = container_of(work, struct iris_cfg, vfr_update_work); + + if (atomic_read(&pcfg->video_update_wo_osd) >= 4) { + if (iris_update_vfr(pcfg, true)) + IRIS_LOGI("enable vfr"); + } else { + if (iris_update_vfr(pcfg, false)) + IRIS_LOGI("disable vfr"); + } +} + +void iris_init_vfr_work(struct iris_cfg *pcfg) +{ + INIT_WORK(&pcfg->vfr_update_work, __iris_update_vfr_work); +} + +void iris_frc_low_latency(bool low_latency) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->frc_low_latency = low_latency; + + IRIS_LOGI("%s(%d) low latency: %d.", __func__, __LINE__, low_latency); +} + +void iris_set_panel_te(u8 panel_te) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->panel_te = panel_te; +} + +void iris_set_n2m_enable(bool enable) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->n2m_enable = enable; +} + +void iris_frc_parameter_init(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct dsi_mode_info *timing; + u32 refresh_rate; + + osd_blending_work.enter_lp_st = MIPI2_LP_FINISH; + + if (!pcfg->panel->cur_mode) + return; + + timing = &pcfg->panel->cur_mode->timing; + refresh_rate = timing->refresh_rate; + IRIS_LOGI("refresh_rate: %d!", refresh_rate); + if ((refresh_rate % 10) != 0) { + refresh_rate = ((refresh_rate + 5) / 10) * 10; + IRIS_LOGW("change refresh_rate from %d to %d!", timing->refresh_rate, refresh_rate); + } + pcfg->frc_setting.out_fps = refresh_rate; + pcfg->frc_setting.default_out_fps = refresh_rate; + pcfg->panel_te = timing->refresh_rate; + pcfg->ap_te = timing->refresh_rate; + pcfg->frc_setting.input_vtotal = DSI_V_TOTAL(timing); + // temp treat display timing same as input timing + pcfg->frc_setting.disp_hres = timing->h_active; + pcfg->frc_setting.disp_vres = timing->v_active; + pcfg->frc_setting.disp_htotal = DSI_H_TOTAL(timing); + pcfg->frc_setting.disp_vtotal = DSI_V_TOTAL(timing); +} + +int32_t iris_parse_frc_setting(struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + + pcfg->frc_enable = false; + pcfg->frc_setting.memc_level = 3; + pcfg->frc_setting.memc_osd = 0; + pcfg->frc_setting.mv_buf_num = 7; + pcfg->frc_setting.in_fps = 24; + pcfg->frc_setting.mv_baseaddr = 0x002c0000; // 7 MV buffers + + // Move panel timing parse to iris_pq_parameter_init(). + /* panel_te, ap_te get too late in IrisService, add pxlw,panel-te and pxlw,ap-te in dtsi */ + pcfg->panel_te = 60; + of_property_read_u32(np, "pxlw,panel-te", &(pcfg->panel_te)); + pcfg->ap_te = 60; + of_property_read_u32(np, "pxlw,ap-te", &(pcfg->ap_te)); + + pcfg->frc_enable = true; + + return rc; +} + +bool iris_get_dual2single_status(void) +{ + u32 rc = 0; + + rc = iris_ocp_read(IRIS_PWIL_CUR_META0, DSI_CMD_SET_STATE_HS); + if ((rc != 0 && (rc & BIT(10)) == 0)) + return true; + + return false; +} + +static void _iris_second_channel_pre(bool dsc_enabled) +{ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe7); +} + +int32_t iris_set_second_channel_power(bool pwr) +{ + bool compression_mode; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + struct iris_update_regval regval; + + if (unlikely(!pcfg2->panel)) { + IRIS_LOGE("%s(), no secondary panel configured!", __func__); + return -EFAULT; + } + + if (pwr) { //on + regval.ip = IRIS_IP_SYS; + regval.opt_id = 0x06; + regval.mask = 0x2000; + regval.value = 0x2000; + iris_update_bitmask_regval_nonread(®val, true); + if (osd_blending_work.enter_lp_st != MIPI2_LP_FINISH) { + IRIS_LOGE("osd_disable_work is still in queue entry"); + osd_blending_work.enter_lp_st = MIPI2_LP_FINISH; + } + + if (pcfg2->iris_osd_autorefresh_enabled) + IRIS_LOGW("osd_autorefresh is not disable before enable osd!"); + else + IRIS_LOGI("osd_autorefresh is disable before enable osd!"); + + if (pcfg2->panel->power_info.refcount == 0) { + IRIS_LOGW("%s(), AP mipi2 tx hasn't been power on.", __func__); + pcfg2->osd_switch_on_pending = true; + } else { + if (pcfg->panel->cur_mode && pcfg->panel->cur_mode->priv_info && pcfg->panel->cur_mode->priv_info->dsc_enabled) + compression_mode = true; + else + compression_mode = false; + + IRIS_LOGI("%s(), iris_pmu_mipi2 on.", __func__); + + /*Power up BSRAM domain if need*/ + iris_pmu_bsram_set(true); + /* power up & config mipi2 domain */ + iris_pmu_mipi2_set(true); + udelay(300); + + iris_set_cfg_index(DSI_PRIMARY); + iris_ulps_source_sel(ULPS_NONE); + _iris_second_channel_pre(compression_mode); + + IRIS_LOGI("%s(), mipi pwr st is true", __func__); + pcfg2->mipi_pwr_st = true; + } + } else { //off + /* power down mipi2 domain */ + regval.ip = IRIS_IP_SYS; + regval.opt_id = 0x06; + regval.mask = 0x2000; + regval.value = 0x0; + iris_update_bitmask_regval_nonread(®val,true); + + iris_pmu_mipi2_set(false); + IRIS_LOGI("%s(), iris_pmu_mipi2 off.", __func__); + pcfg2->mipi_pwr_st = false; + } + + return 0; +} + +void iris_second_channel_post(u32 val) +{ + int i = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + //struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + osd_blending_work.enter_lp_st = MIPI2_LP_SWRST; + iris_send_ipopt_cmds(IRIS_IP_PWIL_2, 0xf1); + + for(i = 0; i < 10; i++) + iris_send_ipopt_cmds(IRIS_IP_PWIL_2, 0xf1); + + IRIS_LOGD("%s(), MIPI2_LP_SWRST", __func__); + /*wait a frame to ensure the pwil_v6 SW_RST is sent*/ + msleep(20); + osd_blending_work.enter_lp_st = MIPI2_LP_POST; + IRIS_LOGD("%s(), MIPI2_LP_POST", __func__); + /* power down mipi2 domain */ + //iris_pmu_mipi2_set(false); + /* bulksram retain on when FRC power on */ + if (pcfg->pwil_mode == PT_MODE) { + if (iris_pmu_frc_get()) + IRIS_LOGI("FRC power on, can't power off bulksram"); + else { + iris_pmu_bsram_set(false); + if (iris_i3c_status_get() == false) + iris_ulps_source_sel(ULPS_MAIN); + } + } + //pcfg->osd_enable = false; + osd_blending_work.enter_lp_st = MIPI2_LP_FINISH; + IRIS_LOGD("%s(), MIPI2_LP_FINISH", __func__); +} + +static void _iris_osd_blending_off(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + IRIS_LOGD("%s, ", __func__); + + iris_set_pwil_mode(pcfg->panel, pcfg->pwil_mode, false, DSI_CMD_SET_STATE_HS); + iris_set_pwil_disp_ctrl(); + iris_psf_mif_efifo_set(pcfg->pwil_mode, false); +} + +static void _iris_osd_blending_on(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + IRIS_LOGD("%s(), ", __func__); + if (pcfg->pwil_mode == PT_MODE) + iris_psf_mif_efifo_set(pcfg->pwil_mode, true); + + iris_set_pwil_mode(pcfg->panel, pcfg->pwil_mode, true, DSI_CMD_SET_STATE_HS); + iris_set_pwil_disp_ctrl(); +} + +int32_t iris_switch_osd_blending(u32 val) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + + if (unlikely(!pcfg2->panel)) { + IRIS_LOGE("%s(), No secondary panel configured!", __func__); + return -EFAULT; + } + + if (val) { + if (pcfg->dual_test & 0x100) { + // check MIPI_RX AUX 2b_page register + uint32_t *payload; + u32 cmd_2b_page; + int count = 0; + + payload = iris_get_ipopt_payload_data(IRIS_IP_RX_2, 0xF0, 2); + while (count < 20) { + cmd_2b_page = iris_ocp_read(0xf1840304, DSI_CMD_SET_STATE_HS); + if (cmd_2b_page != payload[2]) { + count++; + IRIS_LOGW("Warning: cmd_2b_page: %x not right, %d!", cmd_2b_page, count); + usleep_range(2000, 2100); + _iris_second_channel_pre(true); + } else + break; + } + } + pcfg->osd_enable = true; + if (osd_blending_work.enter_lp_st != MIPI2_LP_FINISH) { + // IRIS_LOGE("osd_disable_work is still in queue entry"); + osd_blending_work.enter_lp_st = MIPI2_LP_FINISH; + } + //if (pcfg2->panel->power_info.refcount == 0) { + // IRIS_LOGW("%s: AP mipi2 tx hasn't been power on.", __func__); + // pcfg2->osd_switch_on_pending = true; + //} else + _iris_osd_blending_on(); + pcfg->osd_on = true; + } else { + osd_blending_work.enter_lp_st = MIPI2_LP_PRE; + pcfg->osd_enable = false; + _iris_osd_blending_off(); + pcfg->osd_on = false; + } + + return 0; +} + +int32_t iris_osd_autorefresh(u32 val) +{ + int osd_gpio = -1; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_SECONDARY); + + if (iris_disable_osd_autorefresh) { + pcfg->iris_osd_autorefresh = false; + IRIS_LOGI("%s(), osd autofresh is disable.", __func__); + return 0; + } + + IRIS_LOGI("%s(%d), value: %d", __func__, __LINE__, val); + if (pcfg == NULL) { + IRIS_LOGE("%s(), no secondary display.", __func__); + return -EINVAL; + } + + osd_gpio = pcfg->iris_osd_gpio; + if (!gpio_is_valid(osd_gpio)) { + IRIS_LOGE("%s(), invalid GPIO %d", __func__, osd_gpio); + return -EINVAL; + } + + if (val) { + IRIS_LOGI("%s(), enable osd auto refresh", __func__); + enable_irq(gpio_to_irq(osd_gpio)); + pcfg->iris_osd_autorefresh = true; + } else { + IRIS_LOGI("%s(), disable osd auto refresh", __func__); + disable_irq(gpio_to_irq(osd_gpio)); + pcfg->iris_osd_autorefresh = false; + } + + return 0; +} + +int32_t iris_get_osd_overflow_st(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (atomic_read(&pcfg->osd_irq_cnt) >= 2) + return 1; + + return 0; // overflow, old define +} + +irqreturn_t iris_osd_handler(int irq, void *data) +{ + struct dsi_display *display = data; + struct drm_encoder *enc = NULL; + + if (display == NULL) { + IRIS_LOGE("%s(), invalid display.", __func__); + return IRQ_NONE; + } + + IRIS_LOGV("%s(), irq: %d, display: %s", __func__, irq, display->name); + if (display && display->bridge) + enc = display->bridge->base.encoder; + + if (enc) + sde_encoder_disable_autorefresh_handler(enc); + else + IRIS_LOGW("%s(), no encoder.", __func__); + + return IRQ_HANDLED; +} + +void iris_register_osd_irq(void *disp) +{ + int rc = 0; + int osd_gpio = -1; + struct dsi_display *display = NULL; + struct platform_device *pdev = NULL; + struct iris_cfg *pcfg = NULL; + + if (!iris_is_dual_supported()) + return; + + if (!disp) { + IRIS_LOGE("%s(), invalid display.", __func__); + return; + } + + display = (struct dsi_display *)disp; + if (!iris_virtual_display(display)) + return; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + osd_gpio = pcfg->iris_osd_gpio; + IRIS_LOGI("%s(), for display %s, osd status gpio is %d", + __func__, + display->name, osd_gpio); + if (!gpio_is_valid(osd_gpio)) { + IRIS_LOGE("%s(%d), osd status gpio not specified", + __func__, __LINE__); + return; + } + + pdev = display->pdev; + IRIS_LOGI("%s, display: %s, irq: %d", __func__, display->name, gpio_to_irq(osd_gpio)); + rc = devm_request_irq(&pdev->dev, gpio_to_irq(osd_gpio), iris_osd_handler, + IRQF_TRIGGER_RISING, "OSD_GPIO", display); + if (rc) { + IRIS_LOGE("%s(), IRIS OSD request irq failed", __func__); + return; + } + + disable_irq(gpio_to_irq(osd_gpio)); +} + +static void _iris_osd_irq_cnt_clean(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + atomic_set(&pcfg->osd_irq_cnt, 0); +} + +bool iris_secondary_display_autorefresh(void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + struct iris_cfg *pcfg = NULL; + + if (phys_encoder == NULL) + return false; + + if (phys_encoder->connector == NULL) + return false; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return false; + + display = c_conn->display; + if (display == NULL) + return false; + + if (!iris_virtual_display(display)) + return false; + + pcfg = iris_get_cfg_by_index(DSI_SECONDARY); + IRIS_LOGV("%s(), auto refresh: %s", __func__, + pcfg->iris_osd_autorefresh ? "true" : "false"); + if (!pcfg->iris_osd_autorefresh) { + pcfg->iris_osd_autorefresh_enabled = false; + return false; + } + + pcfg->iris_osd_autorefresh_enabled = true; + _iris_osd_irq_cnt_clean(); + + return true; +} + +void iris_inc_osd_irq_cnt(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + atomic_inc(&pcfg->osd_irq_cnt); + IRIS_LOGD("osd_irq: %d", atomic_read(&pcfg->osd_irq_cnt)); +} + +void iris_frc_prepare(struct iris_cfg *pcfg) +{ + if (pcfg->osd_switch_on_pending) { + struct iris_cfg *pcfg0 = iris_get_cfg_by_index(DSI_PRIMARY); + pcfg->osd_switch_on_pending = false; + //schedule_work(&osd_blending_work.osd_enable_work); + IRIS_LOGI("%s(), set secondary channel power for osd pending", __func__); + mutex_lock(&pcfg0->panel->panel_lock); + iris_set_second_channel_power(true); + mutex_unlock(&pcfg0->panel->panel_lock); + IRIS_LOGI("%s(), finish setting secondary channel power", __func__); + } +} + +void iris_clean_frc_status(struct iris_cfg *pcfg) +{ + if (pcfg->rx_mode == pcfg->tx_mode) + pcfg->pwil_mode = PT_MODE; + else + pcfg->pwil_mode = RFB_MODE; + IRIS_LOGI("%s(), pwil_mode: %d", __func__, pcfg->pwil_mode); + + pcfg->switch_mode = IRIS_MODE_RFB; + pcfg->osd_enable = false; + pcfg->osd_on = false; + pcfg->frc_setting.in_fps_configured = 0; + pcfg->mcu_code_downloaded = false; + if (pcfg->tx_mode == 0) // video mode + iris_set_frc_var_display(0); + pcfg->dynamic_vfr = false; + atomic_set(&pcfg->video_update_wo_osd, 0); + cancel_work_sync(&pcfg->vfr_update_work); + atomic_set(&pcfg->osd_irq_cnt, 0); +} + +int32_t iris_dbgfs_frc_init(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + debugfs_create_u32("disable_osd_autorefresh", 0644, pcfg->dbg_root, + (u32 *)&iris_disable_osd_autorefresh); + + return 0; +} + +static void iris_frc_setting_switch(bool dual) +{ + uint32_t *payload = NULL; + uint32_t process_hres[2]; // 0: single, 1: dual + uint32_t process_vres[2]; + uint32_t mv_buf_number[2]; + uint32_t video_baseaddr[2]; + uint8_t opt_id[2] = {0xb0, 0xb1}; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + int i; + for (i=0; i<2; i++) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, opt_id[i], 2); + mv_buf_number[i] = (payload[2] >> 16) & 0x7; + video_baseaddr[i] = payload[7]; + process_hres[i] = payload[10] & 0xffff; + process_vres[i] = (payload[10] >> 16) & 0xffff; + } + i = dual ? 1 : 0; + pcfg->frc_setting.memc_hres = process_hres[i]; + pcfg->frc_setting.memc_vres = process_vres[i]; + pcfg->frc_setting.mv_buf_num = mv_buf_number[i]; + pcfg->frc_setting.video_baseaddr = video_baseaddr[i]; + + if (process_hres[0] != process_hres[1]) { + iris_scaler_filter_ratio_get(); + IRIS_LOGI("update scaler filter"); + } + payload = iris_get_ipopt_payload_data(IRIS_IP_DSC_ENC_2, dual ? 0xf2 : 0xf1, 2); + pcfg->frc_setting.memc_dsc_bpp = (payload[42] >> 8) & 0xff; + IRIS_LOGD("memc_dsc_bpp: %x", pcfg->frc_setting.memc_dsc_bpp); +} + +void iris_dual_setting_switch(bool dual) +{ + struct iris_ctrl_opt arr_single[] = { + {0x03, 0xa0, 0x01}, // IRIS_IP_PWIL, pwil: ctrl graphic + {0x03, 0xb0, 0x01}, // IRIS_IP_PWIL, pwil: video + {0x03, 0x80, 0x01}, // IRIS_IP_PWIL, pwil: update + {0x0b, 0xf0, 0x01}, // IRIS_IP_SCALER1D, scaler1d + {0x0b, 0xa0, 0x01}, // IRIS_IP_SCALER1D, scaler1d: gc + {0x2f, 0xf0, 0x01}, // IRIS_IP_SCALER1D_2, scaler_pp: init + {0x2d, 0xf0, 0x01}, // IRIS_IP_PSR_MIF, psr_mif: init + {0x11, 0xe2, 0x00}, // IRIS_IP_DMA + }; + struct iris_ctrl_opt arr_dual[] = { + {0x03, 0xa1, 0x01}, // IRIS_IP_PWIL, pwil: ctrl graphic + {0x03, 0xb1, 0x01}, // IRIS_IP_PWIL, pwil: video + {0x03, 0x80, 0x01}, // IRIS_IP_PWIL, pwil: update + {0x0b, 0xf1, 0x01}, // IRIS_IP_SCALER1D, scaler1d + {0x0b, 0xa0, 0x01}, // IRIS_IP_SCALER1D, scaler1d: gc + {0x2f, 0xf1, 0x01}, // IRIS_IP_SCALER1D_2, scaler_pp: init + {0x2d, 0xf1, 0x01}, // IRIS_IP_PSR_MIF, psr_mif: init + {0x11, 0xe2, 0x00}, // IRIS_IP_DMA + }; + struct iris_ctrl_opt *opt_arr = dual ? arr_dual : arr_single; + int len = sizeof(arr_single)/sizeof(struct iris_ctrl_opt); + iris_send_assembled_pkt(opt_arr, len); + IRIS_LOGI("iris_dual_setting_switch, dual: %d, len: %d", dual, len); + iris_frc_setting_switch(dual); + iris_cm_setting_switch(dual); +} + +void iris_frc_dsc_setting(bool dual) +{ + struct iris_ctrl_opt arr_single[] = { + {0x25, 0xf1, 0x01}, // IRIS_IP_DSC_DEN_2, dsc_encoder_frc: init + {0x24, 0xf1, 0x01}, // IRIS_IP_DSC_ENC_2, dsc_encoder_frc: init + {0x11, 0xe8, 0x00}, // IRIS_IP_DMA + }; + struct iris_ctrl_opt arr_dual[] = { + {0x25, 0xf2, 0x01}, // IRIS_IP_DSC_DEN_2 + {0x24, 0xf2, 0x01}, // IRIS_IP_DSC_ENC_2 + {0x11, 0xe8, 0x00}, // IRIS_IP_DMA + }; + struct iris_ctrl_opt *opt_arr = dual ? arr_dual : arr_single; + int len = sizeof(arr_single)/sizeof(struct iris_ctrl_opt); + iris_send_assembled_pkt(opt_arr, len); + IRIS_LOGI("iris_frc_dsc_setting, dual: %d, len: %d", dual, len); +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_frc.h b/techpack/display/msm/dsi/iris/dsi_iris5_frc.h new file mode 100755 index 000000000000..27f0b458b829 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_frc.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef __DSI_IRIS_FRC__ +#define __DSI_IRIS_FRC__ + +struct iris_cfg; +struct device_node; +void iris_init_vfr_work(struct iris_cfg *pcfg); +void iris_frc_low_latency(bool low_latency); +void iris_set_panel_te(u8 panel_te); +void iris_set_n2m_enable(bool enable); +void iris_frc_parameter_init(void); +int32_t iris_parse_frc_setting(struct device_node *np, struct iris_cfg *pcfg); +bool iris_get_dual2single_status(void); +int32_t iris_set_second_channel_power(bool pwr); +void iris_second_channel_post(u32 val); +int32_t iris_switch_osd_blending(u32 val); +int32_t iris_osd_autorefresh(u32 val); +int32_t iris_get_osd_overflow_st(void); +irqreturn_t iris_osd_handler(int irq, void *data); +void iris_frc_prepare(struct iris_cfg *pcfg); +void iris_clean_frc_status(struct iris_cfg *pcfg); +int32_t iris_dbgfs_frc_init(void); +void iris_dual_setting_switch(bool dual); +void iris_frc_dsc_setting(bool dual); + +#endif //__DSI_IRIS_FRC__ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_gpio.c b/techpack/display/msm/dsi/iris/dsi_iris5_gpio.c new file mode 100755 index 000000000000..49de65720dd2 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_gpio.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/debugfs.h> +#include "dsi_display.h" +#include "dsi_panel.h" +#include "dsi_iris5.h" +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_gpio.h" +#include "dsi_iris5_log.h" + + +#define IRIS_GPIO_HIGH 1 +#define IRIS_GPIO_LOW 0 +#define POR_CLOCK 180 /* 0.1 Mhz */ + +static int gpio_pulse_delay = 16 * 16 * 4 * 10 / POR_CLOCK; +static int gpio_cmd_delay = 10; + +int iris_enable_pinctrl(void *dev, void *cfg) +{ + int rc = 0; + struct platform_device *pdev = dev; + struct iris_cfg *pcfg = cfg; + + pcfg->pinctrl.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pcfg->pinctrl.pinctrl)) { + rc = PTR_ERR(pcfg->pinctrl.pinctrl); + IRIS_LOGE("%s(), failed to get pinctrl, return: %d", + __func__, rc); + return -EINVAL; + } + + pcfg->pinctrl.active = pinctrl_lookup_state(pcfg->pinctrl.pinctrl, + "iris_active"); + if (IS_ERR_OR_NULL(pcfg->pinctrl.active)) { + rc = PTR_ERR(pcfg->pinctrl.active); + IRIS_LOGE("%s(), failed to get pinctrl active state, return: %d", + __func__, rc); + return -EINVAL; + } + + pcfg->pinctrl.suspend = pinctrl_lookup_state(pcfg->pinctrl.pinctrl, + "iris_suspend"); + if (IS_ERR_OR_NULL(pcfg->pinctrl.suspend)) { + rc = PTR_ERR(pcfg->pinctrl.suspend); + IRIS_LOGE("%s(), failed to get pinctrl suspend state, retrun: %d", + __func__, rc); + return -EINVAL; + } + + return 0; +} + +int iris_set_pinctrl_state(void *cfg, bool enable) +{ + int rc = 0; + struct pinctrl_state *state; + struct iris_cfg *pcfg = cfg; + + IRIS_LOGI("%s(), set state: %s", __func__, + enable?"active":"suspend"); + if (enable) + state = pcfg->pinctrl.active; + else + state = pcfg->pinctrl.suspend; + + rc = pinctrl_select_state(pcfg->pinctrl.pinctrl, state); + if (rc) + IRIS_LOGE("%s(), failed to set pin state %d, return: %d", + __func__, enable, rc); + + return rc; +} + +/* init one wired command GPIO */ +int iris_init_one_wired(void) +{ + int one_wired_gpio = 0; + int one_wired_status_gpio = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + one_wired_gpio = pcfg->iris_wakeup_gpio; + + IRIS_LOGI("%s(%d)", __func__, __LINE__); + + if (!gpio_is_valid(one_wired_gpio)) { + pcfg->abypss_ctrl.analog_bypass_disable = true; + + IRIS_LOGE("%s(%d), one wired GPIO not configured", + __func__, __LINE__); + return 0; + } + + gpio_direction_output(one_wired_gpio, IRIS_GPIO_LOW); + + one_wired_status_gpio = pcfg->iris_abyp_ready_gpio; + if (!gpio_is_valid(one_wired_status_gpio)) { + IRIS_LOGE("%s(%d), ABYP status GPIO not configured.", + __func__, __LINE__); + return 0; + } + + gpio_direction_input(one_wired_status_gpio); + + return 0; +} + +/* send one wired commands via GPIO */ +void iris_send_one_wired_cmd(IRIS_ONE_WIRE_TYPE type) +{ + int cnt = 0; + u32 start_end_delay = 0; + u32 pulse_delay = 0; + unsigned long flags; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + int one_wired_gpio = pcfg->iris_wakeup_gpio; + const int pulse_count[IRIS_ONE_WIRE_CMD_CNT] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, + }; + + if (!gpio_is_valid(one_wired_gpio)) { + IRIS_LOGE("%s(%d), one wired GPIO not configured", + __func__, __LINE__); + return; + } + + start_end_delay = 16 * 16 * 16 * 10 / POR_CLOCK; /*us*/ + pulse_delay = gpio_pulse_delay; /*us*/ + + IRIS_LOGI("%s(), type: %d, pulse delay: %d, gpio cmd delay: %d", + __func__, type, pulse_delay, gpio_cmd_delay); + + spin_lock_irqsave(&pcfg->iris_1w_lock, flags); + for (cnt = 0; cnt < pulse_count[type]; cnt++) { + gpio_set_value(one_wired_gpio, IRIS_GPIO_HIGH); + udelay(pulse_delay); + gpio_set_value(one_wired_gpio, IRIS_GPIO_LOW); + udelay(pulse_delay); + } + + udelay(gpio_cmd_delay); + spin_unlock_irqrestore(&pcfg->iris_1w_lock, flags); + + udelay(start_end_delay); +} + +int iris_check_abyp_ready(void) +{ + int iris_abyp_ready_gpio = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!gpio_is_valid(pcfg->iris_abyp_ready_gpio)) { + IRIS_LOGE("%s(), ABYP status GPIO is not configured.", __func__); + return -EFAULT; + } + iris_abyp_ready_gpio = gpio_get_value(pcfg->iris_abyp_ready_gpio); + IRIS_LOGI("%s(), ABYP status: %d.", __func__, iris_abyp_ready_gpio); + + return iris_abyp_ready_gpio; +} + +int iris_parse_gpio(void *dev, void *cfg) +{ + struct platform_device *pdev = dev; + struct device_node *of_node = pdev->dev.of_node; + struct iris_cfg *pcfg = cfg; + struct dsi_panel *panel = pcfg->panel; + + if (panel == NULL) { + IRIS_LOGE("%s(), invalid panel", __func__); + return -EINVAL; + } + + IRIS_LOGI("%s(), for [%s], panel type: %s, is secondary: %s", + __func__, + panel->name, panel->type, + panel->is_secondary ? "true" : "false"); + + pcfg->iris_wakeup_gpio = of_get_named_gpio(of_node, + "qcom,iris-wakeup-gpio", 0); + IRIS_LOGI("%s(), wakeup gpio %d", __func__, + pcfg->iris_wakeup_gpio); + if (!gpio_is_valid(pcfg->iris_wakeup_gpio)) + IRIS_LOGW("%s(), wake up gpio is not specified", __func__); + + pcfg->iris_abyp_ready_gpio = of_get_named_gpio(of_node, + "qcom,iris-abyp-ready-gpio", 0); + IRIS_LOGI("%s(), abyp ready status gpio %d", __func__, + pcfg->iris_abyp_ready_gpio); + if (!gpio_is_valid(pcfg->iris_abyp_ready_gpio)) + IRIS_LOGW("%s(), abyp ready gpio is not specified", __func__); + + pcfg->iris_reset_gpio = of_get_named_gpio(of_node, + "qcom,iris-reset-gpio", 0); + IRIS_LOGI("%s(), iris reset gpio %d", __func__, + pcfg->iris_reset_gpio); + if (!gpio_is_valid(pcfg->iris_reset_gpio)) + IRIS_LOGW("%s(), iris reset gpio is not specified", __func__); + + pcfg->iris_vdd_gpio = of_get_named_gpio(of_node, + "qcom,iris-vdd-gpio", 0); + IRIS_LOGI("%s(), iris vdd gpio %d", __func__, + pcfg->iris_vdd_gpio); + if (!gpio_is_valid(pcfg->iris_vdd_gpio)) + IRIS_LOGW("%s(), iris vdd gpio not specified", __func__); + + if (!iris_is_dual_supported()) + return 0; + + pcfg->iris_osd_gpio = pcfg->iris_abyp_ready_gpio; + if (!gpio_is_valid(pcfg->iris_osd_gpio)) + IRIS_LOGW("%s(), osd gpio %d not specified", + __func__, pcfg->iris_osd_gpio); + + return 0; +} + +void iris_request_gpio(void) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct dsi_panel *panel = pcfg->panel; + + IRIS_LOGI("%s(), for [%s] %s, secondary: %i", + __func__, + panel->name, panel->type, panel->is_secondary); + if (panel->is_secondary) + return; + + if (gpio_is_valid(pcfg->iris_vdd_gpio)) { + rc = gpio_request(pcfg->iris_vdd_gpio, "iris_vdd"); + if (rc) + IRIS_LOGW("%s(), failed to request vdd, return: %d", __func__, rc); + } + + if (gpio_is_valid(pcfg->iris_wakeup_gpio)) { + rc = gpio_request(pcfg->iris_wakeup_gpio, "iris_wake_up"); + if (rc) + IRIS_LOGW("%s(), failed to request wake up, return: %d", __func__, rc); + } + + if (gpio_is_valid(pcfg->iris_abyp_ready_gpio)) { + rc = gpio_request(pcfg->iris_abyp_ready_gpio, "iris_abyp_ready"); + if (rc) + IRIS_LOGW("%s(), failed to request abyp ready, return: %d", __func__, rc); + } + + if (gpio_is_valid(pcfg->iris_reset_gpio)) { + rc = gpio_request(pcfg->iris_reset_gpio, "iris_reset"); + if (rc) { + IRIS_LOGW("%s(), failed to request reset, return: %d", __func__, rc); + } + } +} + +void iris_release_gpio(void *cfg) +{ + struct iris_cfg *pcfg = cfg; + struct dsi_panel *panel = pcfg->panel; + + IRIS_LOGI("%s(), for [%s] %s, secondary: %i", + __func__, + panel->name, panel->type, panel->is_secondary); + if (panel->is_secondary) + return; + + if (gpio_is_valid(pcfg->iris_wakeup_gpio)) + gpio_free(pcfg->iris_wakeup_gpio); + if (gpio_is_valid(pcfg->iris_abyp_ready_gpio)) + gpio_free(pcfg->iris_abyp_ready_gpio); + if (gpio_is_valid(pcfg->iris_reset_gpio)) + gpio_free(pcfg->iris_reset_gpio); + if (gpio_is_valid(pcfg->iris_vdd_gpio)) + gpio_free(pcfg->iris_vdd_gpio); +} + +bool iris_vdd_valid(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (gpio_is_valid(pcfg->iris_vdd_gpio)) + return true; + + return false; +} + +void iris_enable_vdd(void) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + IRIS_LOGI("%s(), vdd enable", __func__); + rc = gpio_direction_output(pcfg->iris_vdd_gpio, IRIS_GPIO_HIGH); + if (rc) + IRIS_LOGE("%s(), unable to set dir for iris vdd gpio, return: %d", + __func__, rc); + gpio_set_value(pcfg->iris_vdd_gpio, IRIS_GPIO_HIGH); +} + +void iris_disable_vdd(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + gpio_set_value(pcfg->iris_vdd_gpio, IRIS_GPIO_LOW); +} + +void iris_reset_chip(void) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!gpio_is_valid(pcfg->iris_reset_gpio)) + return; + + rc = gpio_direction_output(pcfg->iris_reset_gpio, IRIS_GPIO_LOW); + if (rc) { + IRIS_LOGE("%s(), unable to set iris reset gpio, return: %d", + __func__, rc); + return; + } + + IRIS_LOGI("%s(), reset start", __func__); + gpio_set_value(pcfg->iris_reset_gpio, IRIS_GPIO_LOW); + usleep_range(1000, 1001); + gpio_set_value(pcfg->iris_reset_gpio, IRIS_GPIO_HIGH); + usleep_range(2000, 2001); + IRIS_LOGI("%s(), reset end", __func__); +} + +void iris_reset_off(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (gpio_is_valid(pcfg->iris_reset_gpio)) + gpio_set_value(pcfg->iris_reset_gpio, IRIS_GPIO_LOW); +} + + +int iris_dbg_gpio_init(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("%s(), create debug dir for iris failed, error %ld", + __func__, PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + debugfs_create_u32("pulse_delay", 0644, pcfg->dbg_root, + (u32 *)&gpio_pulse_delay); + debugfs_create_u32("cmd_delay", 0644, pcfg->dbg_root, + (u32 *)&gpio_cmd_delay); + + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_gpio.h b/techpack/display/msm/dsi/iris/dsi_iris5_gpio.h new file mode 100755 index 000000000000..f63e7965aa21 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_gpio.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef __DSI_IRIS_GPIO__ +#define __DSI_IRIS_GPIO__ + + +typedef enum { + IRIS_POWER_UP_SYS, + IRIS_ENTER_ANALOG_BYPASS, + IRIS_EXIT_ANALOG_BYPASS, + IRIS_POWER_DOWN_SYS, + IRIS_RESET_SYS, + IRIS_FORCE_ENTER_ANALOG_BYPASS, + IRIS_FORCE_EXIT_ANALOG_BYPASS, + IRIS_POWER_UP_MIPI, + IRIS_POWER_DOWN_MIPI, + IRIS_ONE_WIRE_CMD_CNT +} IRIS_ONE_WIRE_TYPE; + +int iris_init_one_wired(void); +void iris_send_one_wired_cmd(IRIS_ONE_WIRE_TYPE type); +int iris_enable_pinctrl(void *dev, void *cfg); +int iris_set_pinctrl_state(void *cfg, bool enable); +int iris_parse_gpio(void *dev, void *cfg); +void iris_request_gpio(void); +void iris_release_gpio(void *cfg); +int iris_check_abyp_ready(void); +bool iris_vdd_valid(void); +void iris_enable_vdd(void); +void iris_disable_vdd(void); +void iris_reset_chip(void); +void iris_reset_off(void); +int iris_dbg_gpio_init(void); + +#endif //__DSI_IRIS_GPIO__ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_i2c.c b/techpack/display/msm/dsi/iris/dsi_iris5_i2c.c new file mode 100755 index 000000000000..820430c7fcf5 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_i2c.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2015-2020. + */ + +//#include <asm-generic/uaccess.h> +#include <linux/fs.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/printk.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/kthread.h> +#include <linux/workqueue.h> +#include <linux/ktime.h> +#include <linux/time.h> +#include "dsi_iris5_i2c.h" + +#define IRIS_COMPATIBLE_NAME "pixelworks,iris-i2c" +#define IRIS_I2C_DRIVER_NAME "pixelworks-i2c" + +#define I2C_DBG_TAG "iris_i2c" +#define IRIS_I2C_DBG +#ifdef IRIS_I2C_DBG +#define iris_i2c_dbg(fmt, args...) pr_debug(I2C_DBG_TAG "[%s:%d]" fmt, __func__, __LINE__, args) +#else +#define iris_i2c_dbg(fmt, args...) do {} while (0) +#endif + +#define MAX_TRANSFER_MSG_LEN 32 +/* + * pixelworks extend i2c + */ +enum { + MSMFB_IRIS_I2C_READ = 0x01, + MSMFB_IRIS_I2C_WRITE = 0X02, +}; + +enum { + ONE_BYTE_REG_LEN = 0x04, + TWO_BYTE_REG_LEN = 0x08, + FOUR_BYTE_REG_LEN = 0x0c, + ONE_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | ONE_BYTE_REG_LEN, + TWO_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | TWO_BYTE_REG_LEN, + FOUR_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | FOUR_BYTE_REG_LEN, + ONE_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | ONE_BYTE_REG_LEN, + TWO_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | TWO_BYTE_REG_LEN, + FOUR_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | FOUR_BYTE_REG_LEN, +}; + +enum { + DBG_I2C_READ = 0x01, + DBG_I2C_WRITE, +}; + +/*iris i2c handle*/ +static struct i2c_client *iris_i2c_handle; + +static int iris_i2c_rw_t(uint32_t type, struct addr_val_i2c *val, int len); + +static int iris_i2c_read_transfer( + struct i2c_adapter *adapter, struct i2c_msg *msgs, int len) +{ + int i = 0; + int pos = 0; + int ret = -1; + + for (i = 0; i < len; i++) { + pos = i << 1; + ret = i2c_transfer(adapter, &msgs[pos], 2); + if (ret < 1) { + pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret); + return -EACCES; + } + } + return 0; +} + +static int iris_i2c_cmd_four_read(struct addr_val_i2c *val, int len) +{ + int i = 0; + int ret = -1; + int pos = 0; + const int reg_len = 5; + const int ret_len = 4; + uint8_t cmd = 0xcc; + uint8_t slave_addr = 0; + uint8_t *data = NULL; + uint8_t *ret_data = NULL; + struct i2c_client *client = iris_i2c_handle; + + /* for ret value need to be N * len + * N is cmd + val+ ret (1+1+1,1+2+2,1+4+4) + */ + uint8_t *nine_data_list = NULL; + struct i2c_msg *msgs = NULL; + + nine_data_list = kmalloc(9 * len * sizeof(nine_data_list[0]), GFP_KERNEL); + if (!nine_data_list) + return -ENOMEM; + + msgs = kmalloc(2 * len * sizeof(msgs[0]), GFP_KERNEL); + if (!msgs) { + kfree(nine_data_list); + nine_data_list = NULL; + return -ENOMEM; + } + + slave_addr = (client->addr & 0xff); + memset(msgs, 0x00, 2 * len * sizeof(msgs[0])); + + for (i = 0; i < len; i++) { + pos = 9 * i; + nine_data_list[pos] = cmd; + nine_data_list[pos + 1] = (val[i].addr & 0xff); + nine_data_list[pos + 2] = ((val[i].addr >> 8) & 0xff); + nine_data_list[pos + 3] = ((val[i].addr >> 16) & 0xff); + nine_data_list[pos + 4] = ((val[i].addr >> 24) & 0xff); + data = &nine_data_list[pos]; + ret_data = &nine_data_list[pos + reg_len]; + + pos = i << 1; + msgs[pos].addr = slave_addr; + msgs[pos].flags = 0; + msgs[pos].buf = data; + msgs[pos].len = reg_len; + + msgs[pos + 1].addr = slave_addr; + msgs[pos + 1].flags = I2C_M_RD; + msgs[pos + 1].buf = ret_data; + msgs[pos + 1].len = ret_len; + } + + ret = iris_i2c_read_transfer(client->adapter, msgs, len); + if (ret != 0) + goto I2C_READ_ERR; + + for (i = 0; i < len; i++) { + pos = 9 * i + 5; + val[i].data = (nine_data_list[pos] << 24) | (nine_data_list[pos + 1] << 16) + | (nine_data_list[pos + 2] << 8) | nine_data_list[pos + 3]; + } + +I2C_READ_ERR: + kfree(nine_data_list); + nine_data_list = NULL; + kfree(msgs); + msgs = NULL; + + return 0; + +} + +static int iris_i2c_send_msg(struct i2c_msg *msgs, int len) +{ + int retry = 0; + int ret = -EINVAL; + struct i2c_client *client = iris_i2c_handle; + + if (msgs == NULL || len < 1) + return ret; + + //pr_err("iris come here send msg\n"); + while (retry < 3) { + ret = i2c_transfer(client->adapter, msgs, len); + if (ret < 1) { + retry++; + pr_err("iris meet with error when send i2c msg ret = %d\n", ret); + i2c_recover_bus(client->adapter); + udelay(100); + } else + break; + } + + if (retry == 3) { + pr_err("iris can not transfer msgs\n"); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, + (uint8_t *)(msgs[0].buf) + 1, 8, false); + return -EINVAL; + } + + return 0; +} + +static int iris_i2c_cmd_four_write(struct addr_val_i2c *val, int len) +{ + int i = 0; + int ret = -1; + int pos = 0; + int mult_val = 0; + int pos_val = 0; + const int reg_len = 9; + const uint8_t cmd = 0xcc; + uint8_t slave_addr = 0; + uint8_t *data = NULL; + struct i2c_client *client = iris_i2c_handle; + struct i2c_msg *msgs = NULL; + + /* for ret value need to be N * len + * N is cmd + addr+ val (1+1+1,1+2+2,1+4+4) + */ + uint8_t *nine_data_list = NULL; + + nine_data_list = kmalloc(9 * len * sizeof(nine_data_list[0]), GFP_KERNEL); + if (!nine_data_list) + return -ENOMEM; + + msgs = kmalloc_array(len, sizeof(msgs[0]), GFP_KERNEL); + if (!msgs) { + kfree(nine_data_list); + nine_data_list = NULL; + return -ENOMEM; + } + + slave_addr = (client->addr & 0xff); + memset(msgs, 0x00, len * sizeof(msgs[0])); + + for (i = 0; i < len; i++) { + pos = reg_len * i; + nine_data_list[pos] = cmd; + nine_data_list[pos + 1] = (val[i].addr & 0xff); + nine_data_list[pos + 2] = ((val[i].addr >> 8) & 0xff); + nine_data_list[pos + 3] = ((val[i].addr >> 16) & 0xff); + nine_data_list[pos + 4] = ((val[i].addr >> 24) & 0xff); + nine_data_list[pos + 5] = ((val[i].data >> 24) & 0xff); + nine_data_list[pos + 6] = ((val[i].data >> 16) & 0xff); + nine_data_list[pos + 7] = ((val[i].data >> 8) & 0xff); + nine_data_list[pos + 8] = (val[i].data & 0xff); + + data = &nine_data_list[pos]; + + msgs[i].addr = slave_addr; + msgs[i].flags = 0; + msgs[i].buf = data; + msgs[i].len = reg_len; + } + + + /* according to I2C_MSM_BAM_CONS_SZ in i2c_msm_v2.h + * the write msg should be less than 32 + */ + if (len <= MAX_TRANSFER_MSG_LEN) { + ret = iris_i2c_send_msg(msgs, len); + if (ret != 0) + goto I2C_WRITE_ERR; + } else { + mult_val = (len / MAX_TRANSFER_MSG_LEN); + pos_val = len - (mult_val * MAX_TRANSFER_MSG_LEN); + for (i = 0; i < mult_val; i++) { + ret = iris_i2c_send_msg( + &msgs[i * MAX_TRANSFER_MSG_LEN], MAX_TRANSFER_MSG_LEN); + if (ret != 0) + goto I2C_WRITE_ERR; + } + + if (pos_val != 0) { + ret = iris_i2c_send_msg(&msgs[i * MAX_TRANSFER_MSG_LEN], pos_val); + if (ret != 0) + goto I2C_WRITE_ERR; + } + } + + ret = 0; + +I2C_WRITE_ERR: + kfree(nine_data_list); + nine_data_list = NULL; + kfree(msgs); + msgs = NULL; + + return ret; + +} + +static int iris_i2c_rw_t(uint32_t type, struct addr_val_i2c *val, int len) +{ + int ret = -1; + + switch (type) { + case FOUR_BYTE_REG_LEN_READ: + ret = iris_i2c_cmd_four_read(val, len); + break; + case FOUR_BYTE_REG_LEN_WRITE: + ret = iris_i2c_cmd_four_write(val, len); + break; + default: + pr_err("can not identify the cmd = %x\n", type); + return -EINVAL; + } + return ret; +} + +/*currently we use four byte*/ +static int iris_i2c_rw(uint32_t type, struct addr_val_i2c *val, int len) +{ + struct i2c_client *client = iris_i2c_handle; + + if (!client) { + pr_err("iris i2c handle is NULL\n"); + return -EACCES; + } + + if (!val || len == 0) { + pr_err("the return buf = %p or len = %d\n", + val, len); + return -EINVAL; + } + + return iris_i2c_rw_t(type, val, len); +} + +static int iris_i2c_single_conver_ocp_read(uint32_t *ptr, uint32_t len) +{ + int ret, i; + struct addr_val_i2c *val_tmp; + uint32_t base_addr = *ptr; + u8 *p = NULL; + + p = kmalloc(sizeof(*val_tmp) * (len+1), GFP_KERNEL); + if (p == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + val_tmp = (struct addr_val_i2c *)p; + pr_err("%s,%d,len=%d\n", __func__, __LINE__, len); + + + for (i = 0; i < len; i++) { + val_tmp[i].addr = base_addr + i*4; + val_tmp[i].data = 0x0; + } + + ret = iris_i2c_rw(FOUR_BYTE_REG_LEN_READ, val_tmp, len); + + for (i = 0; i < len; i++) + ptr[i] = val_tmp[i].data; + + kfree(p); + p = NULL; + + return ret; +} + +static int iris_i2c_burst_conver_ocp_read(uint32_t *ptr, uint32_t dlen) +{ + int i; + int ret = -1; + const uint8_t cmd = 0xfc; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + struct i2c_msg msgs[2]; + + + u8 *iris_payload = NULL; + struct i2c_client *client = iris_i2c_handle; +#if 0 + if (!ptr || dlen < 2) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } +#endif + start_addr = *ptr; + reg_num = dlen; + + slave_addr = (client->addr) & 0xff; + memset(msgs, 0x00, 2 * sizeof(msgs[0])); + + msg_len = reg_num * 4; + + iris_payload = kmalloc(sizeof(iris_payload[0]) * (5+msg_len), GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + + iris_payload[0] = cmd; + iris_payload[1] = (start_addr & 0xff); + iris_payload[2] = ((start_addr >> 8) & 0xff); + iris_payload[3] = ((start_addr >> 16) & 0xff); + iris_payload[4] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 5] = 0x00; + iris_payload[i*4 + 6] = 0x00; + iris_payload[i*4 + 7] = 0x00; + iris_payload[i*4 + 8] = 0x00; + } + + msgs[0].addr = slave_addr; + msgs[0].flags = 0; + msgs[0].buf = iris_payload; + msgs[0].len = 5; + + msgs[1].addr = slave_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = iris_payload+5; + msgs[1].len = msg_len; + + ret = i2c_transfer(client->adapter, msgs, 2); + + if (ret == 2) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + + for (i = 0; i < reg_num; i++) { + ptr[i] = (iris_payload[i*4 + 5]<<24) | + (iris_payload[i*4 + 6]<<16) | + (iris_payload[i*4 + 7]<<8) | + (iris_payload[i*4 + 8]); + } + + kfree(iris_payload); + iris_payload = NULL; + + return ret; + +} + +int iris_i2c_conver_ocp_read(uint32_t *ptr, uint32_t len, bool is_burst) +{ + int ret = -1; + + if (!iris_i2c_handle) + return -EINVAL; + + if (is_burst) + ret = iris_i2c_burst_conver_ocp_read(ptr, len); + else + ret = iris_i2c_single_conver_ocp_read(ptr, len); + + return ret; +} +static int iris_i2c_single_write(struct addr_val_i2c *val, int len) +{ + return iris_i2c_rw(FOUR_BYTE_REG_LEN_WRITE, val, len); +} +int iris_i2c_single_conver_ocp_write(uint32_t *arr, uint32_t dlen) +{ + int ret, i; + struct addr_val_i2c *val_tmp; + u8 *p = NULL; + + if (!iris_i2c_handle) + return -EINVAL; + + p = kmalloc(sizeof(*val_tmp) * (dlen)+1, GFP_KERNEL); + if (p == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + val_tmp = (struct addr_val_i2c *)p; + for (i = 0; i < dlen; i++) { + val_tmp->addr = arr[2*i]; + val_tmp->data = arr[2*i+1]; + val_tmp = val_tmp+1; + } + + ret = iris_i2c_single_write((struct addr_val_i2c *)p, dlen); + kfree(p); + p = NULL; + + return ret; +} + +int iris_i2c_burst_conver_ocp_write(uint32_t base_addr, uint32_t *arr, uint32_t dlen) +{ + + int i; + int ret = -1; + const uint8_t cmd = 0xfc; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + struct i2c_msg msgs; + + u8 *iris_payload = NULL; + u32 *lut_buffer = NULL; + + struct i2c_client *client = iris_i2c_handle; + + if (!iris_i2c_handle) + return -EINVAL; + + if (!arr || dlen < 1) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } + + start_addr = base_addr; + lut_buffer = arr + 1; + reg_num = dlen; + + slave_addr = (client->addr) & 0xff; + + memset(&msgs, 0x00, sizeof(msgs)); + + msg_len = 5 + reg_num * 4; + + iris_payload = kmalloc_array(msg_len, sizeof(iris_payload[0]), GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris3] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + + iris_payload[0] = cmd; + iris_payload[1] = (start_addr & 0xff); + iris_payload[2] = ((start_addr >> 8) & 0xff); + iris_payload[3] = ((start_addr >> 16) & 0xff); + iris_payload[4] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 5] = ((lut_buffer[i] >> 24) & 0xff); + iris_payload[i*4 + 6] = ((lut_buffer[i] >> 16) & 0xff); + iris_payload[i*4 + 7] = ((lut_buffer[i] >> 8) & 0xff); + iris_payload[i*4 + 8] = (lut_buffer[i] & 0xff); + } + + msgs.addr = slave_addr; + msgs.flags = 0; + msgs.buf = iris_payload; + msgs.len = msg_len; + + ret = i2c_transfer(client->adapter, &msgs, 1); + + if (ret == 1) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris3] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + + kfree(iris_payload); + iris_payload = NULL; + + return ret; + +} + +int iris_i2c_conver_ocp_write(uint32_t base_addr, uint32_t *ptr, uint32_t len, bool is_burst) +{ + int ret = 0; + + if (is_burst) + ret = iris_i2c_burst_conver_ocp_write(base_addr, ptr, len-1); + else + ret = iris_i2c_single_conver_ocp_write(ptr, len/2); + + return ret; +} + +int iris_i2c_group_write(struct iris_i2c_msg *iris_i2c_msg, uint32_t iris_i2c_msg_num) +{ + + int i, j, k; + int ret = -1; + const uint8_t cmd = 0xfc; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + struct i2c_msg *msgs; + + u8 *iris_payload = NULL; + u32 *lut_buffer = NULL; + + struct i2c_client *client = iris_i2c_handle; + + if (!iris_i2c_handle) + return -EINVAL; + + if (!iris_i2c_msg || iris_i2c_msg_num < 1) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } + + msgs = kmalloc(sizeof(struct i2c_msg) * iris_i2c_msg_num + 1, GFP_KERNEL); + if (msgs == NULL) { + pr_err("[iris3] %s:%d: allocate memory fails\n", __func__, __LINE__); + return -EINVAL; + } + memset(msgs, 0x00, sizeof(struct i2c_msg) * iris_i2c_msg_num); + + + for (j = 0; j < iris_i2c_msg_num; j++) { + + start_addr = iris_i2c_msg[j].base_addr; + lut_buffer = iris_i2c_msg[j].payload + 1; + reg_num = iris_i2c_msg[j].len - 1; + + slave_addr = (client->addr) & 0xff; + + msg_len = 5 + reg_num * 4; + + iris_payload = kmalloc_array(msg_len, sizeof(iris_payload[0]), GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris3] %s: allocate memory fails\n", __func__); + goto I2C_TRANSFER_ERR; + } + + iris_payload[0] = cmd; + iris_payload[1] = (start_addr & 0xff); + iris_payload[2] = ((start_addr >> 8) & 0xff); + iris_payload[3] = ((start_addr >> 16) & 0xff); + iris_payload[4] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 5] = ((lut_buffer[i] >> 24) & 0xff); + iris_payload[i*4 + 6] = ((lut_buffer[i] >> 16) & 0xff); + iris_payload[i*4 + 7] = ((lut_buffer[i] >> 8) & 0xff); + iris_payload[i*4 + 8] = (lut_buffer[i] & 0xff); + } + + msgs[j].addr = slave_addr; + msgs[j].flags = 0; + msgs[j].buf = iris_payload; + msgs[j].len = msg_len; + } + ret = i2c_transfer(client->adapter, msgs, iris_i2c_msg_num); + + if (ret == iris_i2c_msg_num) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris3] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + +I2C_TRANSFER_ERR: + for (k = 0; k < j; k++) { + kfree(msgs[k].buf); + msgs[k].buf = NULL; + } + kfree(msgs); + msgs = NULL; + + return ret; + +} + +static int iris_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + iris_i2c_handle = client; + return 0; +} + +static int iris_i2c_remove(struct i2c_client *client) +{ + iris_i2c_handle = NULL; + return 0; +} + +static const struct i2c_device_id iris_i2c_id_table[] = { + {IRIS_I2C_DRIVER_NAME, 0}, + {}, +}; + + +static const struct of_device_id iris_match_table[] = { + {.compatible = IRIS_COMPATIBLE_NAME,}, + { }, +}; + +static struct i2c_driver plx_i2c_driver = { + .driver = { + .name = IRIS_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = iris_match_table, + }, + .probe = iris_i2c_probe, + .remove = iris_i2c_remove, + .id_table = iris_i2c_id_table, +}; + + +int iris_i2c_bus_init(void) +{ + int ret; + + pr_err("%s initialize begin!\n", __func__); + ret = i2c_add_driver(&plx_i2c_driver); + if (ret != 0) + pr_err("i2c add driver fail: %d\n", ret); + return 0; +} + +void iris_i2c_bus_exit(void) +{ + i2c_del_driver(&plx_i2c_driver); + iris_i2c_remove(iris_i2c_handle); +} + + +module_init(iris_i2c_bus_init); +module_exit(iris_i2c_bus_exit); + diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_i2c.h b/techpack/display/msm/dsi/iris/dsi_iris5_i2c.h new file mode 100755 index 000000000000..1ff8abc5bb57 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_i2c.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2015-2020. + */ +#ifndef DSI_IRIS_I2C_H +#define DSI_IRIS_I2C_H + +#include <linux/i2c.h> +#include <linux/of.h> + +struct addr_val_i2c { + uint32_t addr; + uint32_t data; +}; +struct iris_i2c_msg { + uint32_t *payload; + uint32_t len; + uint32_t base_addr; +}; + + +int iris_i2c_bus_init(void); +void iris_i2c_bus_exit(void); +int iris_i2c_conver_ocp_read(uint32_t *ptr, uint32_t len, bool is_burst); +int iris_i2c_conver_ocp_write(uint32_t base_addr, uint32_t *ptr, uint32_t len, bool is_burst); +int iris_i2c_burst_conver_ocp_write(uint32_t base_addr, uint32_t *arr, uint32_t dlen); +int iris_i2c_single_conver_ocp_write(uint32_t *arr, uint32_t dlen); +int iris_i2c_group_write(struct iris_i2c_msg *iris_i2c_msg, uint32_t iris_i2c_msg_num); + +#endif diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_i3c.c b/techpack/display/msm/dsi/iris/dsi_iris5_i3c.c new file mode 100755 index 000000000000..7594635acb34 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_i3c.c @@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2015-2020. + */ + + +#include <linux/fs.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/printk.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/kthread.h> +#include <linux/workqueue.h> +#include <linux/ktime.h> +#include <linux/time.h> +#include "dsi_iris5_i3c.h" + +#define IRIS_COMPATIBLE_NAME "pixelworks,iris" +#define IRIS_I2C_DRIVER_NAME "pixelworks" + +#define I2C_DBG_TAG "iris_i2c" +#define IRIS_I2C_DBG +#ifdef IRIS_I2C_DBG +#define iris_i2c_dbg(fmt, args...) pr_debug(I2C_DBG_TAG "[%s:%d]" fmt, __func__, __LINE__, args) +#else +#define iris_i2c_dbg(fmt, args...) do {} while (0) +#endif + +#define MAX_TRANSFER_MSG_LEN 32 +static bool iris_i3c_status; //1: busy, 0: idle + +/* + *pixelworks extend i2c + */ +enum { + MSMFB_IRIS_I2C_READ = 0x01, + MSMFB_IRIS_I2C_WRITE = 0X02, +}; + +enum { + ONE_BYTE_REG_LEN = 0x04, + TWO_BYTE_REG_LEN = 0x08, + FOUR_BYTE_REG_LEN = 0x0c, + ONE_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | ONE_BYTE_REG_LEN, + TWO_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | TWO_BYTE_REG_LEN, + FOUR_BYTE_REG_LEN_READ = (MSMFB_IRIS_I2C_READ << 16) | FOUR_BYTE_REG_LEN, + ONE_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | ONE_BYTE_REG_LEN, + TWO_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | TWO_BYTE_REG_LEN, + FOUR_BYTE_REG_LEN_WRITE = (MSMFB_IRIS_I2C_WRITE << 16) | FOUR_BYTE_REG_LEN, +}; + +enum { + DBG_I2C_READ = 0x01, + DBG_I2C_WRITE, +}; + + +/*iris i2c handle*/ +static struct i2c_client *iris_i2c_handle; + +static int iris_i2c_rw_t(uint32_t type, struct addr_val *val, int len); + +static int iris_i2c_read_transfer( + struct i2c_adapter *adapter, struct i2c_msg *msgs, int len) +{ + int i = 0; + int pos = 0; + int ret = -1; + + for (i = 0; i < len; i++) { + pos = i << 1; + ret = i2c_transfer(adapter, &msgs[pos], 2); + if (ret < 1) { + pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret); + return -EACCES; + } + } + return 0; +} + + +static int iris_i2c_cmd_four_read(struct addr_val *val, int len) +{ + + int i = 0; + int ret = -1; + int pos = 0; + const int reg_len = 8; + const int ret_len = 4; + uint8_t slave_addr = 0; + uint8_t *data = NULL; + uint8_t *ret_data = NULL; + struct i2c_client *client = iris_i2c_handle; + + + /* for ret value need to be N * len + * N is cmd + val+ ret (4+1+1,4+2+2,4+4+4) + */ + uint8_t *twelve_data_list = NULL; + struct i2c_msg *msgs = NULL; + + twelve_data_list = kmalloc(12 * len * sizeof(twelve_data_list[0]), GFP_KERNEL); + if (!twelve_data_list) + return -ENOMEM; + + msgs = kmalloc(2 * len * sizeof(msgs[0]), GFP_KERNEL); + if (!msgs) { + kfree(twelve_data_list); + twelve_data_list = NULL; + return -ENOMEM; + } + + slave_addr = (client->addr & 0xff); + memset(msgs, 0x00, 2 * len * sizeof(msgs[0])); + + for (i = 0; i < len; i++) { + pos = 12 * i; + twelve_data_list[pos] = 0x8; + twelve_data_list[pos + 1] = 0x00; + twelve_data_list[pos + 2] = 0x04; + twelve_data_list[pos + 3] = 0x00; + twelve_data_list[pos + 4] = (val[i].addr & 0xff); + twelve_data_list[pos + 5] = ((val[i].addr >> 8) & 0xff); + twelve_data_list[pos + 6] = ((val[i].addr >> 16) & 0xff); + twelve_data_list[pos + 7] = ((val[i].addr >> 24) & 0xff); + data = &twelve_data_list[pos]; + ret_data = &twelve_data_list[pos + reg_len]; + + pos = i << 1; + msgs[pos].addr = slave_addr; + msgs[pos].flags = 0; + msgs[pos].buf = data; + msgs[pos].len = reg_len; + + msgs[pos + 1].addr = slave_addr; + msgs[pos + 1].flags = I2C_M_RD; + msgs[pos + 1].buf = ret_data; + msgs[pos + 1].len = ret_len; + } + + ret = iris_i2c_read_transfer(client->adapter, msgs, len); + if (ret != 0) + goto I2C_READ_ERR; + + for (i = 0; i < len; i++) { + pos = 12 * i + 8; + val[i].data = (twelve_data_list[pos] << 0) | + (twelve_data_list[pos + 1] << 8) | + (twelve_data_list[pos + 2] << 16) | + (twelve_data_list[pos + 3] << 24); + } +I2C_READ_ERR: + //pr_err("%s: line:%d, ret:%d\n", __func__,__LINE__, ret); + kfree(twelve_data_list); + twelve_data_list = NULL; + kfree(msgs); + msgs = NULL; + + return ret; + +} + +static int iris_i2c_send_msg(struct i2c_msg *msgs, int len) +{ + int retry = 0; + int ret = -EINVAL; + struct i2c_client *client = iris_i2c_handle; + + if (msgs == NULL || len < 1) + return ret; + + while (retry < 3) { + ret = i2c_transfer(client->adapter, msgs, len); + if (ret < 1) { + retry++; + pr_err("iris meet with error when send i2c msg ret = %d\n", ret); + i2c_recover_bus(client->adapter); + udelay(100); + } else + break; + } + + if (retry == 3) { + pr_err("iris can not transfer msgs\n"); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, + (uint8_t *)(msgs[0].buf) + 1, 8, false); + return -EINVAL; + } + + return 0; +} + +#define MAX_CHAIN_TRANSFER_LEN 2 +static int iris_i2c_cmd_four_write(struct addr_val *val, int len) +{ + + int i = 0; + int ret = -1; + int pos = 0; + int mult_val = 0; + int pos_val = 0; + uint16_t byte_count = 0; + + + uint8_t slave_addr = 0; + uint8_t *data = NULL; + struct i2c_client *client = iris_i2c_handle; + struct i2c_msg *msgs = NULL; + + /* for ret value need to be N * len + * N is cmd + addr+ val (4+1+1,4+2+2,4+4+4) + */ + uint8_t *twelve_data_list = NULL; + + twelve_data_list = kmalloc(12 * len * sizeof(twelve_data_list[0]), GFP_KERNEL); + if (!twelve_data_list) { + pr_err("[iris] %s: fail to alloc memory\n", __func__); + return -ENOMEM; + } + + msgs = kmalloc(len * sizeof(msgs[0]), GFP_KERNEL); + if (!msgs) { + kfree(twelve_data_list); + twelve_data_list = NULL; + return -ENOMEM; + } + + slave_addr = (client->addr & 0xff); + memset(msgs, 0x00, len * sizeof(msgs[0])); + byte_count = 8 + 4; + pos = 0; + + + for (i = 0; i < len; i++) { + pos = 12 * i; + twelve_data_list[pos] = 0x4; + twelve_data_list[pos + 1] = 0x00; + twelve_data_list[pos + 2] = byte_count&0xff; + twelve_data_list[pos + 3] = (byte_count>>8)&0xff; + twelve_data_list[pos + 4] = (val[i].addr & 0xff); + twelve_data_list[pos + 5] = ((val[i].addr >> 8) & 0xff); + twelve_data_list[pos + 6] = ((val[i].addr >> 16) & 0xff); + twelve_data_list[pos + 7] = ((val[i].addr >> 24) & 0xff); + twelve_data_list[pos + 8] = ((val[i].data >> 0) & 0xff); + twelve_data_list[pos + 9] = ((val[i].data >> 8) & 0xff); + twelve_data_list[pos + 10] = ((val[i].data >> 16) & 0xff); + twelve_data_list[pos + 11] = ((val[i].data >> 24) & 0xff); + data = &twelve_data_list[pos]; + msgs[i].addr = slave_addr; + msgs[i].flags = 0; + msgs[i].buf = data; + msgs[i].len = byte_count; + } + + + + /* according to I2C_MSM_BAM_CONS_SZ in i2c_msm_v2.h + * the write msg should be less than 32 + */ + if (len <= MAX_TRANSFER_MSG_LEN) { + ret = iris_i2c_send_msg(msgs, len); + if (ret != 0) + goto I2C_WRITE_ERR; + } else { + mult_val = (len / MAX_TRANSFER_MSG_LEN); + pos_val = len - (mult_val * MAX_TRANSFER_MSG_LEN); + for (i = 0; i < mult_val; i++) { + ret = iris_i2c_send_msg( + &msgs[i * MAX_TRANSFER_MSG_LEN], MAX_TRANSFER_MSG_LEN); + if (ret != 0) + goto I2C_WRITE_ERR; + } + + if (pos_val != 0) { + ret = iris_i2c_send_msg(&msgs[i * MAX_TRANSFER_MSG_LEN], pos_val); + if (ret != 0) + goto I2C_WRITE_ERR; + } + } + + ret = 0; + +I2C_WRITE_ERR: + kfree(twelve_data_list); + twelve_data_list = NULL; + kfree(msgs); + msgs = NULL; + + return ret; + +} + +static int iris_i2c_rw_t(uint32_t type, struct addr_val *val, int len) +{ + int ret = -1; + + switch (type) { + case FOUR_BYTE_REG_LEN_READ: + ret = iris_i2c_cmd_four_read(val, len); + break; + case FOUR_BYTE_REG_LEN_WRITE: + ret = iris_i2c_cmd_four_write(val, len); + break; + default: + pr_err("can not identify the cmd = %x\n", type); + return -EINVAL; + } + return ret; +} + +/*currently we use four byte*/ +static int iris_i2c_rw(uint32_t type, struct addr_val *val, int len) +{ + struct i2c_client *client = iris_i2c_handle; + + if (!client) { + pr_err("iris i2c handle is NULL\n"); + return -EACCES; + } + + if (!val || len == 0) { + pr_err("the return buf = %p or len = %d\n", val, len); + return -EINVAL; + } + + return iris_i2c_rw_t(type, val, len); +} + +static int iris_i2c_ocp_single_read(uint32_t *ptr, uint32_t len) +{ + int ret, i; + struct addr_val *val_tmp; + uint32_t base_addr = *ptr; + u8 *p = NULL; + + p = kmalloc(sizeof(*val_tmp) * (len+1), GFP_KERNEL); + if (p == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + val_tmp = (struct addr_val *)p; + + for (i = 0; i < len; i++) { + val_tmp[i].addr = base_addr + i*4; + val_tmp[i].data = 0x0; + } + + ret = iris_i2c_rw(FOUR_BYTE_REG_LEN_READ, val_tmp, len); + + for (i = 0; i < len; i++) + ptr[i] = val_tmp[i].data; + + kfree(p); + p = NULL; + + return ret; +} + +static int iris_i2c_ocp_burst_read(uint32_t *ptr, uint32_t dlen) +{ + int i; + int ret = -1; + uint16_t byte_count = 0; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + struct i2c_msg msgs[2]; + + u8 *iris_payload = NULL; + struct i2c_client *client = iris_i2c_handle; + + start_addr = *ptr; + byte_count = dlen*4; + reg_num = byte_count/4; + slave_addr = (client->addr) & 0xff; + memset(msgs, 0x00, 2 * sizeof(msgs[0])); + + msg_len = byte_count; + + iris_payload = kmalloc(sizeof(iris_payload[0]) * (8+msg_len), GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + if ((dlen == 0) || (dlen > 65536/4)) { + pr_err("[iris] %s: len equal to 0 or too long\n", __func__); + kfree(iris_payload); + return -EINVAL; + } + + iris_payload[0] = 0x8; + iris_payload[1] = 0x00; + iris_payload[2] = (byte_count&0xff); + iris_payload[3] = ((byte_count>>8)&0xff); + iris_payload[4] = (start_addr & 0xff); + iris_payload[5] = ((start_addr >> 8) & 0xff); + iris_payload[6] = ((start_addr >> 16) & 0xff); + iris_payload[7] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 8] = 0x00; + iris_payload[i*4 + 9] = 0x00; + iris_payload[i*4 + 10] = 0x00; + iris_payload[i*4 + 11] = 0x00; + } + + msgs[0].addr = slave_addr; + msgs[0].flags = 0; + msgs[0].buf = iris_payload; + msgs[0].len = 8; + + msgs[1].addr = slave_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = iris_payload+8; + msgs[1].len = msg_len; + + ret = i2c_transfer(client->adapter, msgs, 2); + + if (ret == 2) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + + for (i = 0; i < reg_num; i++) { + ptr[i] = (iris_payload[i*4 + 8]<<0) | + (iris_payload[i*4 + 9]<<8) | + (iris_payload[i*4 + 10]<<16)| + (iris_payload[i*4 + 11]<<24); + } + + kfree(iris_payload); + iris_payload = NULL; + + return ret; + +} + +int iris_i2c_ocp_read(uint32_t *ptr, uint32_t len, bool is_burst) +{ + int ret = -1; + + if (!iris_i2c_handle) + return -EINVAL; + + if (is_burst) + ret = iris_i2c_ocp_burst_read(ptr, len); + else + ret = iris_i2c_ocp_single_read(ptr, len); + + return ret; +} +static int iris_i2c_single_write(struct addr_val *val, int len) +{ + return iris_i2c_rw(FOUR_BYTE_REG_LEN_WRITE, val, len); +} + +int iris_i2c_ocp_burst_write(uint32_t *arr, uint32_t dlen) +{ + + int i; + int ret = -1; + uint16_t byte_count = 0; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + u8 cmd = 0; + struct i2c_msg msgs; + + u8 *iris_payload = NULL; + u32 *lut_buffer = NULL; + struct i2c_client *client = iris_i2c_handle; + + if (!arr || dlen < 1) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } + + if ((dlen == 0) || (dlen > 65536/4)) { + pr_err("[iris] %s: len equal to 0 or too long\n", __func__); + return -EINVAL; + } + + start_addr = arr[0]; + cmd = 0x00; + lut_buffer = arr + 1; + reg_num = dlen; + + slave_addr = (client->addr) & 0xff; + + memset(&msgs, 0x00, sizeof(msgs)); + + msg_len = 8 + reg_num * 4; + + iris_payload = kmalloc(sizeof(iris_payload[0]) * msg_len + 1, GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + byte_count = reg_num*4 + 4 + 4; + + iris_payload[0] = cmd; + iris_payload[1] = 0x00; + iris_payload[2] = (byte_count & 0xff); + iris_payload[3] = ((byte_count>>8) & 0xff); + iris_payload[4] = (start_addr & 0xff); + iris_payload[5] = ((start_addr >> 8) & 0xff); + iris_payload[6] = ((start_addr >> 16) & 0xff); + iris_payload[7] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 8] = ((lut_buffer[i] >> 0) & 0xff); + iris_payload[i*4 + 9] = ((lut_buffer[i] >> 8) & 0xff); + iris_payload[i*4 + 10] = ((lut_buffer[i] >> 16) & 0xff); + iris_payload[i*4 + 11] = ((lut_buffer[i] >> 24) & 0xff); + } + + msgs.addr = slave_addr; + msgs.flags = 0; + msgs.buf = iris_payload; + msgs.len = msg_len; + + ret = i2c_transfer(client->adapter, &msgs, 1); + + if (ret == 1) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + + kfree(iris_payload); + iris_payload = NULL; + + return ret; + +} + +int iris_i2c_ocp_single_write(uint32_t *arr, uint32_t dlen) +{ + int ret, i; + struct addr_val *val_tmp; + u8 *p = NULL; + uint32_t tlen = dlen; + + p = kmalloc(sizeof(*val_tmp) * (tlen+1), GFP_KERNEL); + if (p == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + val_tmp = (struct addr_val *)p; + for (i = 0; i < tlen; i++) { + val_tmp->addr = arr[2*i]; + val_tmp->data = arr[2*i+1]; + val_tmp = val_tmp + 1; + } + + ret = iris_i2c_single_write((struct addr_val *)p, tlen); + kfree(p); + p = NULL; + + return ret; +} + +int iris_i2c_ocp_write(uint32_t *ptr, uint32_t len, bool is_burst) +{ + int ret = 0; + + if (!iris_i2c_handle) + return -EINVAL; + + if (is_burst) + ret = iris_i2c_ocp_burst_write(ptr, len); + else + ret = iris_i2c_ocp_single_write(ptr, len); + + return ret; +} + +int iris_i2c_direct_write(uint32_t *arr, uint32_t dlen, uint32_t type) +{ + + int i; + int ret = -1; + uint16_t byte_count = 0; + uint16_t ocp_type = 0; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + u8 cmd = 0; + struct i2c_msg msgs; + + u8 *iris_payload = NULL; + u32 *lut_buffer = NULL; + struct i2c_client *client = iris_i2c_handle; + + if (!arr || dlen < 1) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } + + if ((dlen == 0) || (dlen > 65536/4)) { + pr_err("[iris] %s: len equal to 0 or too long\n", __func__); + return -EINVAL; + } + + ocp_type = type >> 12 | 0x000c; + start_addr = arr[0]; + cmd = ocp_type & 0xff; + lut_buffer = arr + 1; + reg_num = dlen; + + slave_addr = (client->addr) & 0xff; + + memset(&msgs, 0x00, sizeof(msgs)); + + msg_len = 8 + reg_num * 4; + + iris_payload = kmalloc(sizeof(iris_payload[0]) * msg_len + 1, GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris] %s: allocate memory fails\n", __func__); + return -EINVAL; + } + + byte_count = reg_num*4 + 4 + 4; + + iris_payload[0] = cmd; + iris_payload[1] = ((ocp_type>>8) & 0xff); + iris_payload[2] = (byte_count & 0xff); + iris_payload[3] = ((byte_count>>8) & 0xff); + iris_payload[4] = (start_addr & 0xff); + iris_payload[5] = ((start_addr >> 8) & 0xff); + iris_payload[6] = ((start_addr >> 16) & 0xff); + iris_payload[7] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 8] = ((lut_buffer[i] >> 0) & 0xff); + iris_payload[i*4 + 9] = ((lut_buffer[i] >> 8) & 0xff); + iris_payload[i*4 + 10] = ((lut_buffer[i] >> 16) & 0xff); + iris_payload[i*4 + 11] = ((lut_buffer[i] >> 24) & 0xff); + } + + msgs.addr = slave_addr; + msgs.flags = 0; + msgs.buf = iris_payload; + msgs.len = msg_len; + + ret = i2c_transfer(client->adapter, &msgs, 1); + + if (ret == 1) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris] %s: i2c_transfer failed, ret=%d\n", __func__, ret); + } + + kfree(iris_payload); + iris_payload = NULL; + + return ret; + +} + +int iris_i2c_burst_write(struct iris_i2c_msg *iris_i2c_msg, uint32_t iris_i2c_msg_num) +{ + + int i, j, k; + int ret = -1; + uint16_t byte_count = 0; + uint16_t ocp_type = 0; + u32 msg_len = 0; + u8 slave_addr = 0; + uint32_t reg_num = 0; + u32 start_addr = 0; + u8 cmd = 0; + struct i2c_msg *msgs; + + u8 *iris_payload = NULL; + u32 *lut_buffer = NULL; + struct i2c_client *client = iris_i2c_handle; + + if (!iris_i2c_msg || iris_i2c_msg_num < 1) { + pr_err("the parameter is not right\n"); + return -EINVAL; + } + + msgs = kmalloc(sizeof(struct i2c_msg) * iris_i2c_msg_num + 1, GFP_KERNEL); + if (msgs == NULL) { + pr_err("[iris] %s:%d: allocate memory fails\n", __func__, __LINE__); + return -EINVAL; + } + memset(msgs, 0x00, sizeof(struct i2c_msg) * iris_i2c_msg_num); + + for (j = 0; j < iris_i2c_msg_num; j++) { + ocp_type = 0; + if ((iris_i2c_msg[j].base_addr & 0x0f) == 0x0c) + ocp_type = iris_i2c_msg[j].base_addr >> 12 | 0x000c; + start_addr = iris_i2c_msg[j].payload[0]; + cmd = ocp_type & 0xff; + lut_buffer = iris_i2c_msg[j].payload + 1; + reg_num = iris_i2c_msg[j].len - 1; + + slave_addr = (client->addr) & 0xff; + + msg_len = 8 + reg_num * 4; + + iris_payload = NULL; + iris_payload = kmalloc(sizeof(iris_payload[0]) * msg_len + 1, GFP_KERNEL); + if (iris_payload == NULL) { + pr_err("[iris] %s %d: allocate memory fails\n", __func__, __LINE__); + goto I2C_TRANSFER_ERR; + } + + byte_count = reg_num*4 + 4 + 4; + + iris_payload[0] = cmd; + iris_payload[1] = ((ocp_type>>8) & 0xff); + iris_payload[2] = (byte_count & 0xff); + iris_payload[3] = ((byte_count>>8) & 0xff); + iris_payload[4] = (start_addr & 0xff); + iris_payload[5] = ((start_addr >> 8) & 0xff); + iris_payload[6] = ((start_addr >> 16) & 0xff); + iris_payload[7] = ((start_addr >> 24) & 0xff); + + for (i = 0; i < reg_num; i++) { + iris_payload[i*4 + 8] = ((lut_buffer[i] >> 0) & 0xff); + iris_payload[i*4 + 9] = ((lut_buffer[i] >> 8) & 0xff); + iris_payload[i*4 + 10] = ((lut_buffer[i] >> 16) & 0xff); + iris_payload[i*4 + 11] = ((lut_buffer[i] >> 24) & 0xff); + } + + msgs[j].addr = slave_addr; + msgs[j].flags = 0; + msgs[j].buf = iris_payload; + msgs[j].len = msg_len; + + } + + ret = i2c_transfer(client->adapter, msgs, iris_i2c_msg_num); + + if (ret == iris_i2c_msg_num) { + ret = 0; + } else { + ret = ret < 0 ? ret : -EIO; + pr_err("[iris] %s: i2c_transfer failed, ret = %d\n", __func__, ret); + } + + +I2C_TRANSFER_ERR: + for (k = 0; k < j; k++) { + kfree(msgs[k].buf); + msgs[k].buf = NULL; + } + kfree(msgs); + msgs = NULL; + return ret; + +} + +void iris_i3c_status_set(bool enable) +{ + iris_i3c_status = enable; + + pr_info("%s: %d\n", __func__, enable); +} + +bool iris_i3c_status_get(void) +{ + return iris_i3c_status; +} + +static int iris_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + pr_err("%s,%d: %p\n", __func__, __LINE__, iris_i2c_handle); + iris_i2c_handle = client; + pr_err("%s,%d: %p\n", __func__, __LINE__, iris_i2c_handle); + return 0; +} + +static int iris_i2c_remove(struct i2c_client *client) +{ + iris_i2c_handle = NULL; + return 0; +} + +static const struct i2c_device_id iris_i2c_id_table[] = { + {IRIS_I2C_DRIVER_NAME, 0}, + {}, +}; + + +static const struct of_device_id iris_match_table[] = { + {.compatible = IRIS_COMPATIBLE_NAME,}, + { }, +}; + +static struct i2c_driver plx_i2c_driver = { + .driver = { + .name = IRIS_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = iris_match_table, + }, + .probe = iris_i2c_probe, + .remove = iris_i2c_remove, + .id_table = iris_i2c_id_table, +}; + + +int iris_i3c_bus_init(void) +{ + int ret; + + pr_err("%s,%d: initialize begin!\n", __func__, __LINE__); + iris_i3c_status = false; + iris_i2c_handle = NULL; + ret = i2c_add_driver(&plx_i2c_driver); + pr_err("%s,%d: ret = %d\n", __func__, __LINE__, ret); + if (ret != 0) + pr_err("i2c add driver fail: %d\n", ret); + return 0; +} + +void iris_i3c_bus_exit(void) +{ + i2c_del_driver(&plx_i2c_driver); + iris_i2c_remove(iris_i2c_handle); +} + +module_init(iris_i3c_bus_init); +module_exit(iris_i3c_bus_exit); + diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_i3c.h b/techpack/display/msm/dsi/iris/dsi_iris5_i3c.h new file mode 100755 index 000000000000..e385a8ad6905 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_i3c.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2015-2020. + */ +#ifndef DSI_IRIS_I3C_H +#define DSI_IRIS_I3C_H + +#include <linux/i2c.h> +#include <linux/of.h> +#include "dsi_iris5_i2c.h" + +#define I2C_LEGACY_CMD_ENABLE 0 + +#define IRIS_CMD_I2C_SR 0x09 +#define IRIS_CMD_I2C_BR 0x08 +#define IRIS_CMD_I2C_SW 0x04 +#define IRIS_CMD_I2C_BW 0x00 +#define IRIS_CMD_I2C_DW 0x0C +#define IRIS_CMD_I2C_BSW 0x05 +#define IRIS_CMD_I2C_LUT 0x0F + +struct addr_val { + uint32_t addr; + uint32_t data; +}; + +enum PATH_TYPE { + PATH_I2C = 0, + PATH_DSI, +}; + +int iris_i2c_byte_read(uint32_t reg_offset, uint32_t *read_buf); +int iris_i2c_byte_write(uint32_t reg_offset, uint32_t value); +int iris_i2c_read(struct addr_val *val, int len, bool is_burst); +int iris_i2c_write(uint32_t *arr, int len, bool is_burst); +int iris_i2c_bus_init(void); +void iris_i2c_bus_exit(void); +int iris_i2c_ocp_burst_write(uint32_t *arr, uint32_t dlen); +int iris_i2c_ocp_single_write(uint32_t *arr, uint32_t dlen); +int iris_i2c_ocp_write(uint32_t *ptr, uint32_t len, bool is_burst); +int iris_i2c_ocp_read(uint32_t *ptr, uint32_t len, bool is_burst); +int iris_i2c_direct_write(uint32_t *arr, uint32_t dlen, uint32_t type); +int iris_i2c_burst_write(struct iris_i2c_msg *iris_i2c_msg, uint32_t iris_i2c_msg_num); +void iris_i3c_status_set(bool enable); +bool iris_i3c_status_get(void); + + +#endif diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.c b/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.c new file mode 100755 index 000000000000..068e5aed9ddc --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.c @@ -0,0 +1,1269 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include "dsi_iris5_api.h" +#include "dsi_iris5.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_lut.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_ioctl.h" +#include "dsi_iris5_i3c.h" +#include "dsi_iris5_loop_back.h" +#include "dsi_iris5_frc.h" +#include "dsi_iris5_log.h" + +// for game station settings via i2c +uint32_t CM_CNTL[14] = { + 0xf0560000, 0x8020e000, + 0xf0560000, 0x820e000, + 0xf0560008, 0x00000000, + 0xf056000c, 0x6e, + 0xf056000c, 0x5f, + 0xf0560110, 0x00000000, + 0xf0560140, 0x00000100 +}; + +// 0: mipi, 1: i2c +static int adb_type; +static int iris_i2c_ver = 1; + +static int mdss_mipi_dsi_command(void __user *values) +{ + struct msmfb_mipi_dsi_cmd cmd; + + char read_response_buf[16] = {0}; + struct dsi_cmd_desc desc = { + .msg.rx_buf = &read_response_buf, + .msg.rx_len = 16 + }; + struct dsi_panel_cmd_set cmdset = { + .count = 1, + .cmds = &desc + }; + int ret; + struct iris_cfg *pcfg = iris_get_cfg(); + + struct iris_ocp_dsi_tool_input iris_ocp_input = {0, 0, 0, 0, 0}; + + ret = copy_from_user(&cmd, values, sizeof(cmd)); + if (ret) { + IRIS_LOGE("can not copy from user"); + return -EPERM; + } + + IRIS_LOGD("#### %s:%d vc=%u d=%02x f=%hu l=%hu", __func__, __LINE__, + cmd.vc, cmd.dtype, cmd.flags, cmd.length); + + IRIS_LOGD("#### %s:%d %x, %x, %x", __func__, __LINE__, + cmd.iris_ocp_type, cmd.iris_ocp_addr, cmd.iris_ocp_size); + + if (cmd.length < SZ_4K && cmd.payload) { + desc.msg.tx_buf = vmalloc(cmd.length); + if (!desc.msg.tx_buf) + return -ENOMEM; + ret = copy_from_user((char *)desc.msg.tx_buf, cmd.payload, cmd.length); + if (ret) { + ret = -EPERM; + goto err; + } + } else + return -EINVAL; + + desc.msg.type = cmd.dtype; + desc.msg.channel = cmd.vc; + desc.last_command = (cmd.flags & MSMFB_MIPI_DSI_COMMAND_LAST) > 0; + desc.msg.flags |= ((cmd.flags & MSMFB_MIPI_DSI_COMMAND_ACK) > 0 ? MIPI_DSI_MSG_REQ_ACK : 0); + desc.msg.tx_len = cmd.length; + desc.post_wait_ms = 0; + desc.msg.ctrl = 0; + + if (cmd.flags & MSMFB_MIPI_DSI_COMMAND_ACK) + desc.msg.flags = desc.msg.flags | DSI_CTRL_CMD_READ; + + if (cmd.flags & MSMFB_MIPI_DSI_COMMAND_HS) + cmdset.state = DSI_CMD_SET_STATE_HS; + + mutex_lock(&pcfg->panel->panel_lock); + + if (cmd.flags & MSMFB_MIPI_DSI_COMMAND_TO_PANEL) { + if (iris_get_abyp_mode(pcfg->panel) == PASS_THROUGH_MODE) + iris_pt_send_panel_cmd(pcfg->panel, &cmdset); + else + iris_dsi_send_cmds(pcfg->panel, cmdset.cmds, cmdset.count, cmdset.state); + } else if (cmd.flags & MSMFB_MIPI_DSI_COMMAND_T) { + u32 pktCnt = (cmd.iris_ocp_type >> 8) & 0xFF; + + //only test LUT send command + if ((cmd.iris_ocp_type & 0xF) == PXLW_DIRECTBUS_WRITE) { + u8 lut_type = (cmd.iris_ocp_type >> 8) & 0xFF; + u8 lut_index = (cmd.iris_ocp_type >> 16) & 0xFF; + u8 lut_parse = (cmd.iris_ocp_type >> 24) & 0xFF; + u32 lut_pkt_index = cmd.iris_ocp_addr; + + if (lut_parse) // only parse firmware when value is not zero + iris_parse_lut_cmds(0); + iris_send_lut(lut_type, lut_index, lut_pkt_index); + } else { // test ocp wirte + if (pktCnt > DSI_CMD_CNT) + pktCnt = DSI_CMD_CNT; + + if (cmd.iris_ocp_size < OCP_MIN_LEN) + cmd.iris_ocp_size = OCP_MIN_LEN; + + if (cmd.iris_ocp_size > 4096) //CID89803 + cmd.iris_ocp_size = 4096; + + iris_ocp_input.iris_ocp_type = cmd.iris_ocp_type & 0xF; + iris_ocp_input.iris_ocp_cnt = pktCnt; + iris_ocp_input.iris_ocp_addr = cmd.iris_ocp_addr; + iris_ocp_input.iris_ocp_value = cmd.iris_ocp_value; + iris_ocp_input.iris_ocp_size = cmd.iris_ocp_size; + + if (pktCnt) + iris_write_test_muti_pkt(pcfg->panel, &iris_ocp_input); + else + iris_write_test(pcfg->panel, cmd.iris_ocp_addr, cmd.iris_ocp_type & 0xF, cmd.iris_ocp_size); + //iris_ocp_bitmask_write(ctrl,cmd.iris_ocp_addr,cmd.iris_ocp_size,cmd.iris_ocp_value); + } + } else + iris_dsi_send_cmds(pcfg->panel, cmdset.cmds, cmdset.count, cmdset.state); + + mutex_unlock(&pcfg->panel->panel_lock); + + if (cmd.flags & MSMFB_MIPI_DSI_COMMAND_ACK) { + // Both length of cmd.response and read_response_buf are 16. + memcpy(cmd.response, read_response_buf, sizeof(cmd.response)); + } + ret = copy_to_user(values, &cmd, sizeof(cmd)); + if (ret) + ret = -EPERM; +err: + vfree(desc.msg.tx_buf); + return ret; +} + + +int iris_operate_tool(struct msm_iris_operate_value *argp) +{ + int ret = -1; + uint32_t parent_type = 0; + uint32_t display_type = 0; + struct iris_cfg *pcfg = NULL; + + // FIXME: copy_from_user() is failed. + // ret = copy_from_user(&configure, argp, sizeof(configure)); + // if (ret) { + // pr_err("1st %s type = %d, value = %d\n", + // __func__, configure.type, configure.count); + // return -EPERM; + // } + IRIS_LOGI("%s type = %d, value = %d", __func__, argp->type, argp->count); + + display_type = (argp->type >> 16) & 0xff; + pcfg = iris_get_cfg_by_index(display_type); + if (pcfg == NULL || pcfg->valid < PARAM_PARSED) { + IRIS_LOGE("Target display does not exist!"); + return -EPERM; + } + + parent_type = argp->type & 0xff; + switch (parent_type) { + case IRIS_OPRT_TOOL_DSI: + ret = mdss_mipi_dsi_command(argp->values); + break; + default: + IRIS_LOGE("could not find right opertat type = %d", argp->type); + ret = -EINVAL; + break; + } + return ret; +} + +static bool iris_special_config(u32 type) +{ + switch (type) { + case IRIS_OSD_ENABLE: + case IRIS_OSD_AUTOREFRESH: + case IRIS_OSD_OVERFLOW_ST: + case IRIS_DBG_KERNEL_LOG_LEVEL: + case USER_DEMO_WND: + case IRIS_MEMC_LEVEL: + case IRIS_WAIT_VSYNC: + case IRIS_CHIP_VERSION: + case IRIS_FW_UPDATE: + return true; + } + + return false; +} + +static bool _iris_is_valid_type(u32 display, u32 type) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(display); + + if (type >= IRIS_CONFIG_TYPE_MAX) + return false; + + if (!iris_special_config(type) + && type != IRIS_ANALOG_BYPASS_MODE + && pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) + return false; + + if (type != IRIS_DBG_KERNEL_LOG_LEVEL + && pcfg->chip_ver == IRIS3_CHIP_VERSION) + return false; + + return true; +} + +static int _iris_configure(u32 display, u32 type, u32 value) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(display); + struct iris_cfg *pcfg1 = iris_get_cfg_by_index(DSI_PRIMARY); + struct iris_setting_info *iris_setting = iris_get_setting(); + struct quality_setting *pqlt_cur_setting = &iris_setting->quality_cur; + + // Always use primary display. + iris_set_cfg_index(DSI_PRIMARY); + switch (type) { + case IRIS_PEAKING: + pqlt_cur_setting->pq_setting.peaking = value & 0xf; + if (pqlt_cur_setting->pq_setting.peaking > 4) + goto error; + + iris_peaking_level_set(pqlt_cur_setting->pq_setting.peaking); + break; + case IRIS_CM_6AXES: + pqlt_cur_setting->pq_setting.cm6axis = value & 0x3; + iris_cm_6axis_level_set(pqlt_cur_setting->pq_setting.cm6axis); + break; + case IRIS_CM_FTC_ENABLE: + pqlt_cur_setting->cmftc = value; + iris_cm_ftc_enable_set(pqlt_cur_setting->cmftc); + break; + case IRIS_S_CURVE: + pqlt_cur_setting->scurvelevel = value & 0x3; + if (pqlt_cur_setting->scurvelevel > 2) + goto error; + + iris_scurve_enable_set(pqlt_cur_setting->scurvelevel); + break; + case IRIS_CM_COLOR_TEMP_MODE: + pqlt_cur_setting->pq_setting.cmcolortempmode = value & 0x3; + if (pqlt_cur_setting->pq_setting.cmcolortempmode > 2) + goto error; + + iris_cm_colortemp_mode_set(pqlt_cur_setting->pq_setting.cmcolortempmode); + break; + case IRIS_CM_COLOR_GAMUT_PRE: + iris_cm_color_gamut_pre_set(value & 0x03); + break; + case IRIS_CM_COLOR_GAMUT: + pqlt_cur_setting->pq_setting.cmcolorgamut = value; + if (pqlt_cur_setting->pq_setting.cmcolorgamut > 6) + goto error; + + iris_cm_color_gamut_set(pqlt_cur_setting->pq_setting.cmcolorgamut); + break; + case IRIS_DBC_LCE_POWER: + if (value == 0) + iris_dbclce_power_set(false); + else if (value == 1) + iris_dbclce_power_set(true); + else if (value == 2) + iris_lce_dynamic_pmu_mask_set(false); + else if (value == 3) + iris_lce_dynamic_pmu_mask_set(true); + + break; + case IRIS_DBC_LCE_DATA_PATH: + iris_dbclce_datapath_set(value & 0x01); + break; + case IRIS_LCE_MODE: + if (pqlt_cur_setting->pq_setting.lcemode != (value & 0x1)) { + pqlt_cur_setting->pq_setting.lcemode = value & 0x1; + iris_lce_mode_set(pqlt_cur_setting->pq_setting.lcemode); + } + break; + case IRIS_LCE_LEVEL: + if (pqlt_cur_setting->pq_setting.lcelevel != (value & 0x7)) { + pqlt_cur_setting->pq_setting.lcelevel = value & 0x7; + if (pqlt_cur_setting->pq_setting.lcelevel > 5) + goto error; + + iris_lce_level_set(pqlt_cur_setting->pq_setting.lcelevel); + } + break; + case IRIS_GRAPHIC_DET_ENABLE: + pqlt_cur_setting->pq_setting.graphicdet = value & 0x1; + iris_lce_graphic_det_set(pqlt_cur_setting->pq_setting.graphicdet); + break; + case IRIS_AL_ENABLE: + + if (pqlt_cur_setting->pq_setting.alenable != (value & 0x1)) { + pqlt_cur_setting->pq_setting.alenable = value & 0x1; + + /*check the case here*/ + if (pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) + iris_lce_al_set(pqlt_cur_setting->pq_setting.alenable); + else + iris_ambient_light_lut_set(iris_sdr2hdr_lut2ctl_get()); + } + break; + case IRIS_DBC_LEVEL: + pqlt_cur_setting->pq_setting.dbc = value & 0x3; + iris_dbc_level_set(pqlt_cur_setting->pq_setting.dbc); + break; + case IRIS_BLC_PWM_ENABLE: + iris_pwm_enable_set(value & 0x1); + break; + case IRIS_DEMO_MODE: + pqlt_cur_setting->pq_setting.demomode = value & 0x3; + break; + case IRIS_DYNAMIC_POWER_CTRL: + if (value & 0x01) { + IRIS_LOGI(" [%s, %d] open psr_mif osd first address eco.", __func__, __LINE__); + iris_psf_mif_dyn_addr_set(true); + iris_dynamic_power_set(value & 0x01); + } else { + IRIS_LOGI(" [%s, %d] close psr_mif osd first address eco.", __func__, __LINE__); + iris_dynamic_power_set(value & 0x01); + iris_psf_mif_dyn_addr_set(false); + } + break; + case IRIS_DMA_LOAD: + iris_dma_trigger_load(); + break; + case IRIS_SDR2HDR: + iris_set_sdr2hdr_mode((value & 0xf00) >> 8); + value = value & 0xff; + if (value/10 == 4) {/*magic code to enable YUV input.*/ + iris_set_yuv_input(true); + value -= 40; + } else if (value/10 == 6) { + iris_set_HDR10_YCoCg(true); + value -= 60; + } else if (value == 55) { + iris_set_yuv_input(true); + return 0; + } else if (value == 56) { + iris_set_yuv_input(false); + return 0; + } else { + iris_set_yuv_input(false); + iris_set_HDR10_YCoCg(false); + } + + if (pqlt_cur_setting->pq_setting.sdr2hdr > SDR709_2_2020 || value > SDR709_2_2020) + goto error; + if (pqlt_cur_setting->pq_setting.sdr2hdr != value) { + pqlt_cur_setting->pq_setting.sdr2hdr = value; + + iris_sdr2hdr_level_set(pqlt_cur_setting->pq_setting.sdr2hdr); + } + break; + case IRIS_READING_MODE: + pqlt_cur_setting->pq_setting.readingmode = value & 0x1; + iris_reading_mode_set(pqlt_cur_setting->pq_setting.readingmode); + break; + case IRIS_COLOR_TEMP_VALUE: + pqlt_cur_setting->colortempvalue = value; + if (pqlt_cur_setting->pq_setting.cmcolortempmode == IRIS_COLOR_TEMP_MANUL) + iris_cm_color_temp_set(); + break; + case IRIS_CCT_VALUE: + pqlt_cur_setting->cctvalue = value; + if (pqlt_cur_setting->pq_setting.cmcolortempmode == IRIS_COLOR_TEMP_AUTO) + iris_cm_color_temp_set(); + break; + case IRIS_LUX_VALUE: + /* move to iris_configure_ex*/ + pqlt_cur_setting->luxvalue = value; + if (pqlt_cur_setting->pq_setting.alenable == 1) { + + if (pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) + iris_lce_lux_set(); + else + iris_ambient_light_lut_set(iris_sdr2hdr_lut2ctl_get()); + } + break; + case IRIS_HDR_MAXCLL: + pqlt_cur_setting->maxcll = value; + break; + case IRIS_ANALOG_BYPASS_MODE: + if (value == pcfg->abypss_ctrl.abypass_mode) { + IRIS_LOGD("Same bypass mode"); + break; + } + IRIS_LOGI("%s(), switch Iris mode to: %u", __func__, value); + if (value == ANALOG_BYPASS_MODE) { + iris_panel_nits_set(0, true, value); + iris_quality_setting_off(); + iris_abypass_switch_proc(pcfg->display, value, true, true); + } else + iris_abypass_switch_proc(pcfg->display, value, false, true); + break; + case IRIS_DBG_LOOP_BACK_MODE: + pcfg->loop_back_mode = value; + break; + case IRIS_HDR_PANEL_NITES_SET: + if (pqlt_cur_setting->al_bl_ratio != value) { + pqlt_cur_setting->al_bl_ratio = value; + iris_panel_nits_set(value, false, pqlt_cur_setting->pq_setting.sdr2hdr); + } + break; + case IRIS_PEAKING_IDLE_CLK_ENABLE: + iris_peaking_idle_clk_enable(value & 0x01); + break; + case IRIS_CM_MAGENTA_GAIN: + iris_cm_6axis_seperate_gain(IRIS_MAGENTA_GAIN_TYPE, value & 0x3f); + break; + case IRIS_CM_RED_GAIN: + iris_cm_6axis_seperate_gain(IRIS_RED_GAIN_TYPE, value & 0x3f); + break; + case IRIS_CM_YELLOW_GAIN: + iris_cm_6axis_seperate_gain(IRIS_YELLOW_GAIN_TYPE, value & 0x3f); + break; + case IRIS_CM_GREEN_GAIN: + iris_cm_6axis_seperate_gain(IRIS_GREEN_GAIN_TYPE, value & 0x3f); + break; + case IRIS_CM_BLUE_GAIN: + iris_cm_6axis_seperate_gain(IRIS_BLUE_GAIN_TYPE, value & 0x3f); + break; + case IRIS_CM_CYAN_GAIN: + iris_cm_6axis_seperate_gain(IRIS_CYAN_GAIN_TYPE, value & 0x3f); + break; + case IRIS_DBC_LED_GAIN: + iris_dbc_led0d_gain_set(value & 0x3f); + break; + case IRIS_SCALER_FILTER_LEVEL: + iris_scaler_filter_update(SCALER_INPUT, value & 0x7); + break; + case IRIS_SCALER_PP_FILTER_LEVEL: + iris_scaler_filter_update(SCALER_PP, value & 0x1); + break; + case IRIS_HDR_PREPARE: + if ((value == 0) || ((value == 1) && !iris_get_debug_cap()) || (value == 2)) + iris_hdr_csc_prepare(); + else if (value == 3) + iris_set_skip_dma(true); + break; + case IRIS_HDR_COMPLETE: + if ((value == 3) || (value == 5)) + iris_set_skip_dma(false); + if ((value == 0) || ((value == 1) && !iris_get_debug_cap())) + iris_hdr_csc_complete(value); + else if (value >= 2) + iris_hdr_csc_complete(value); + + if (value != 2 && value != 4) { + if (pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) + iris_panel_nits_set(0, true, value); + else + iris_panel_nits_set(PANEL_BL_MAX_RATIO, false, value); + } + break; + case IRIS_DEBUG_CAP: + iris_set_debug_cap(value & 0x01); + break; + case IRIS_FW_UPDATE: + // Need do multi-thread protection. + if (value <= 2) {//CID100675 + /* before parsing firmware, free ip & opt buffer which alloc for LUT, + * if loading firmware failed before, need realloc seq space after + * updating firmware + */ + u8 firmware_status = iris_get_fw_status(); + + iris_free_ipopt_buf(IRIS_LUT_PIP_IDX); + iris_parse_lut_cmds(value); + if (firmware_status == FIRMWARE_LOAD_FAIL) { + iris_free_seq_space(); + iris_alloc_seq_space(); + } + if (iris_get_fw_status() == FIRMWARE_LOAD_SUCCESS) { + if (pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE) { + iris_cm_color_gamut_set(pqlt_cur_setting->pq_setting.cmcolorgamut); + iris_scaler_gamma_enable(false, 1); + } + iris_update_fw_status(FIRMWARE_IN_USING); + } + } + break; + case IRIS_DBG_KERNEL_LOG_LEVEL: + iris_set_loglevel(value); + break; + case IRIS_MODE_SET: + iris_mode_switch_proc(value); + break; + case IRIS_VIDEO_FRAME_RATE_SET: + iris_set_video_frame_rate_ms(value); + break; + case IRIS_OUT_FRAME_RATE_SET: + iris_set_out_frame_rate(value); + break; + case IRIS_OSD_ENABLE: + if (pcfg1->iris_initialized == false) { + IRIS_LOGI("iris not initialized"); + break; + } + if ((value == 1) || (value == 0)) { + IRIS_LOGI("call iris_switch_osd_blending(%d)", value); + iris_switch_osd_blending(value); + } else if (value == 0x10) { + IRIS_LOGI("power on iris mipi2 rx"); + iris_set_second_channel_power(true); + } else if (value == 0x20) { + IRIS_LOGI("reset pwil_v6, power off bulksram"); + iris_second_channel_post(value); + } else if (value == 0x21) { + IRIS_LOGI("power off iris mipi2 rx"); + iris_set_second_channel_power(false); + } else if (value == 0x40) { + iris_dom_set(0); + } else if (value == 0x41) { + iris_dom_set(2); + } else if (value == 0x80 || value == 0x81) { + pcfg1->dual_setting = value == 0x81; + if (pcfg->dual_test & 0x10) + pcfg1->dual_setting = true; + + if (!(pcfg->dual_test & 0x4)) + iris_dual_setting_switch(pcfg1->dual_setting); + } else + IRIS_LOGE("IRIS_OSD_ENABLE, invalid val=%d", value); + break; + case IRIS_OSD_AUTOREFRESH: + // Always use secondary display. + iris_osd_autorefresh(value); + break; + case IRIS_FRC_LOW_LATENCY: + iris_frc_low_latency(value); + break; + case IRIS_PANEL_TE: + iris_set_panel_te(value); + break; + case IRIS_AP_TE: + iris_set_ap_te(value); + break; + case IRIS_N2M_ENABLE: + iris_set_n2m_enable(value); + break; + case IRIS_WAIT_VSYNC: + return iris_wait_vsync(); + case IRIS_MEMC_LEVEL: + if (value <= 3) { + pcfg1->frc_setting.memc_level = value; + pcfg1->frc_setting.short_video = 0; + } else if (value >= 4 && value <= 7) { + pcfg1->frc_setting.memc_level = value - 4; + pcfg1->frc_setting.short_video = 1; + } else if (value >= 8 && value <= 11) { + pcfg1->frc_setting.memc_level = value - 8; + pcfg1->frc_setting.short_video = 2; + } + break; + case IRIS_MEMC_OSD: + pcfg1->frc_setting.memc_osd = value; + break; + case USER_DEMO_WND: + if (value > 5) + goto error; + iris_fi_demo_window(value); + break; + case IRIS_CHIP_VERSION: + pcfg1->chip_value[0] = value; + break; + default: + goto error; + } + + return 0; + +error: + return -EINVAL; + +} + +int iris_configure(u32 display, u32 type, u32 value) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + int rc = 0; + + IRIS_LOGI("%s(), display: %u, type: 0x%04x(%u), value: %#x(%u), current Iris mode: %d", + __func__, + display, type, type, value, value, pcfg->abypss_ctrl.abypass_mode); + if (!_iris_is_valid_type(display, type)) + return -EPERM; + + switch (type) { + case IRIS_DEMO_MODE: + case IRIS_HDR_MAXCLL: + case IRIS_DEBUG_CAP: + case IRIS_VIDEO_FRAME_RATE_SET: + case IRIS_OUT_FRAME_RATE_SET: + case IRIS_OSD_AUTOREFRESH: + case IRIS_DBG_KERNEL_LOG_LEVEL: + case IRIS_FRC_LOW_LATENCY: + case IRIS_N2M_ENABLE: + case IRIS_WAIT_VSYNC: + case IRIS_MEMC_LEVEL: + case IRIS_MEMC_OSD: + case USER_DEMO_WND: + case IRIS_CHIP_VERSION: + /* don't lock panel_lock */ + return _iris_configure(display, type, value); + } + + mutex_lock(&pcfg->panel->panel_lock); + rc = _iris_configure(display, type, value); + mutex_unlock(&pcfg->panel->panel_lock); + return rc; +} + +int iris_configure_t(uint32_t display, u32 type, void __user *argp) +{ + int ret = -1; + uint32_t value = 0; + + ret = copy_from_user(&value, argp, sizeof(uint32_t)); + if (ret) { + IRIS_LOGE("can not copy from user"); + return -EPERM; + } + + ret = iris_configure(display, type, value); + return ret; +} + +static int _iris_configure_ex(u32 display, u32 type, u32 count, u32 *values) +{ + int ret = -1; + struct iris_cfg *pcfg = iris_get_cfg_by_index(display); + struct iris_setting_info *iris_setting = iris_get_setting(); + struct quality_setting *pqlt_cur_setting = &iris_setting->quality_cur; + struct msmfb_iris_ambient_info iris_ambient; + struct msmfb_iris_maxcll_info iris_maxcll; + struct msmfb_iris_ambient_info *iris_ambient_lut = NULL; + struct msmfb_iris_maxcll_info *iris_maxcll_lut = NULL; + uint8_t i = 0; + u32 TempValue = 0; + bool is_phone; + u32 LutPos = 0; + + if (!_iris_is_valid_type(display, type)) + return -EPERM; + + // Always use primary display. + iris_set_cfg_index(DSI_PRIMARY); + switch (type) { + case IRIS_LUX_VALUE: + iris_ambient = *(struct msmfb_iris_ambient_info *)(values); + iris_ambient_lut = iris_get_ambient_lut(); + iris_ambient_lut->ambient_lux = iris_ambient.ambient_lux; + pqlt_cur_setting->luxvalue = iris_ambient_lut->ambient_lux; + + if (iris_ambient.lut_lut2_payload != NULL) { + ret = copy_from_user(iris_ambient_lut->lut_lut2_payload, iris_ambient.lut_lut2_payload, sizeof(uint32_t)*LUT_LEN); + if (ret) { + IRIS_LOGE("can not copy from user sdr2hdr"); + goto error1; + } + LutPos = iris_sdr2hdr_lut2ctl_get(); + if (LutPos == 15) { + LutPos = 0; + iris_update_ambient_lut(AMBINET_SDR2HDR_LUT, 1); + } else if (LutPos == 1) + LutPos = 0; + else if (!LutPos) + LutPos = 1; + iris_update_ambient_lut(AMBINET_SDR2HDR_LUT, LutPos); + } else if (iris_sdr2hdr_lut2ctl_get() == 0xFFE00000) + LutPos = 0xFFE00000; + else + LutPos = 0; + + if (pqlt_cur_setting->pq_setting.alenable == 1) { + if (pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) { + iris_sdr2hdr_lut2ctl_set(LutPos); + iris_lce_lux_set(); + } else + iris_ambient_light_lut_set(LutPos); + } else + iris_sdr2hdr_lut2ctl_set(LutPos); + break; + case IRIS_HDR_MAXCLL: + iris_maxcll_lut = iris_get_maxcll_info(); + iris_maxcll = *(struct msmfb_iris_maxcll_info *)(values); + iris_maxcll_lut->mMAXCLL = iris_maxcll.mMAXCLL; + + if (iris_maxcll.lut_luty_payload != NULL) { + ret = copy_from_user(iris_maxcll_lut->lut_luty_payload, iris_maxcll.lut_luty_payload, sizeof(uint32_t)*LUT_LEN); + if (ret) { + IRIS_LOGE("can not copy lut y from user sdr2hdr"); + goto error1; + } + } + if (iris_maxcll.lut_lutuv_payload != NULL) { + ret = copy_from_user(iris_maxcll_lut->lut_lutuv_payload, iris_maxcll.lut_lutuv_payload, sizeof(uint32_t)*LUT_LEN); + if (ret) { + IRIS_LOGE("can not copy lut uv from user sdr2hdr"); + goto error1; + } + } + LutPos = iris_sdr2hdr_lutyctl_get(); + if (!LutPos) + LutPos = 1; + else if ((LutPos == 15) || (LutPos == 1)) + LutPos = 0; + iris_update_maxcll_lut(AMBINET_HDR_GAIN, LutPos); + iris_maxcll_lut_set(LutPos); + break; + case IRIS_CCF1_UPDATE: + /* Nothing to do for Iirs5*/ + break; + case IRIS_CCF2_UPDATE: + /* Nothing to do for Iirs5*/ + break; + case IRIS_HUE_SAT_ADJ: + IRIS_LOGD("cm csc value: csc0 = 0x%x, csc1 = 0x%x, csc2 = 0x%x, csc3 = 0x%x, csc4 = 0x%x", values[0], values[1], values[2], values[3], values[4]); + IRIS_LOGD("game mode %d", values[5]); + if (values[5] == 1) { + for (i = 0; i <= 4; i++) { + if (pcfg->iris_i2c_write) { + if (pcfg->iris_i2c_write(CM_CNTL[10] + i*4, values[i]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x, val=0x%x", CM_CNTL[10] + i*4, values[i]); + } else { + IRIS_LOGE("Game Station is not connected"); + } + } + } else { + iris_cm_csc_level_set(IRIS_IP_CM, &values[0]); + } + break; + case IRIS_CONTRAST_DIMMING: + IRIS_LOGI("dpp csc value: csc0 = 0x%x, csc1 = 0x%x, csc2 = 0x%x, csc3 = 0x%x, csc4 = 0x%x", + values[0], values[1], values[2], values[3], values[4]); + iris_cm_csc_level_set(IRIS_IP_DPP, &values[0]); + break; + case IRIS_COLOR_TEMP_VALUE: + is_phone = (count > 1) ? (values[1] == 0) : true; + pqlt_cur_setting->colortempvalue = values[0]; + + if (is_phone) { + if (count > 3) { + pqlt_cur_setting->min_colortempvalue = values[2]; + pqlt_cur_setting->max_colortempvalue = values[3]; + } else { + pqlt_cur_setting->min_colortempvalue = 0; + pqlt_cur_setting->max_colortempvalue = 0; + } + if (pqlt_cur_setting->pq_setting.cmcolortempmode == IRIS_COLOR_TEMP_MANUL) + iris_cm_color_temp_set(); + } else { + TempValue = iris_cm_ratio_set_for_iic(); + IRIS_LOGD("set reg=0x%x, val=0x%x", CM_CNTL[4], TempValue); + if (pcfg->iris_i2c_write) { + if (pcfg->iris_i2c_write(CM_CNTL[4], TempValue) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x, val=0x%x", CM_CNTL[4], TempValue); + } else { + IRIS_LOGE("Game Station is not connected"); + } + } + break; + case IRIS_DBG_TARGET_REGADDR_VALUE_SET: + if (adb_type == 0) { + iris_ocp_write_val(values[0], values[1]); + } else if (adb_type == 1) { + if (iris_i2c_ver == 0) { + if (pcfg->iris_i2c_write) { + if (pcfg->iris_i2c_write(values[0], values[1]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x, val=0x%x", values[0], values[1]); + } else { + IRIS_LOGE("Game Station is not connected"); + } + } else { + IRIS_LOGD("addr = %x, value = %x\n", values[0], values[1]); + iris_i2c_ocp_single_write(values, 1); + } + } + break; + case IRIS_DBG_TARGET_REGADDR_VALUE_SET2: + iris_ocp_write_vals(values[0], values[1], count-2, values+2); + break; + case IRIS_CM_6AXES: + // phone + pqlt_cur_setting->pq_setting.cm6axis = values[0] & 0x3; + iris_cm_6axis_level_set(pqlt_cur_setting->pq_setting.cm6axis); + + // game station + if (pcfg->iris_i2c_write) { + if (pcfg->iris_i2c_write(CM_CNTL[0], values[1] ? CM_CNTL[3] : CM_CNTL[1]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x", CM_CNTL[0]); + else if (pcfg->iris_i2c_write(CM_CNTL[12], CM_CNTL[13]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x", CM_CNTL[12]); + } else { + IRIS_LOGE("Game Station is not connected"); + } + break; + case IRIS_CM_COLOR_TEMP_MODE: + // phone + pqlt_cur_setting->pq_setting.cmcolortempmode = values[0] & 0x3; + if (pqlt_cur_setting->pq_setting.cmcolortempmode > 2) + goto error; + + iris_cm_colortemp_mode_set(pqlt_cur_setting->pq_setting.cmcolortempmode); + + // game station + if (pcfg->iris_i2c_write) { + if (pcfg->iris_i2c_write(CM_CNTL[6], values[1] ? CM_CNTL[9] : CM_CNTL[7]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x", CM_CNTL[6]); + else if (pcfg->iris_i2c_write(CM_CNTL[12], CM_CNTL[13]) < 0) + IRIS_LOGE("i2c set reg fails, reg=0x%x", CM_CNTL[12]); + } else { + IRIS_LOGE("Game Station is not connected"); + } + break; + case IRIS_CSC_MATRIX: + if (count > 9) { + if (values[0] == 1) + iris_cm_csc_level_set(IRIS_IP_CM, &values[2]); + else if (values[0] == 2) + iris_cm_csc_level_set(IRIS_IP_DPP, &values[2]); + else + return -EPERM; + } else + return -EPERM; + break; + case IRIS_DBG_SEND_PACKAGE: + ret = iris_send_ipopt_cmds(values[0], values[1]); + IRIS_LOGD("iris config sends package: ip: %#x, opt: %#x, send: %d.", + values[0], values[1], ret); + break; + case IRIS_MEMC_OSD_PROTECT: + IRIS_LOGD("OSD protect setting: Top_left_pos = 0x%x, bot_right_pos = 0x%x, OSDwinID = 0x%x, OSDwinIDEn = 0x%x, DynCompensate = 0x%x", + values[0], values[1], values[2], values[3], values[4]); + ret = iris_fi_osd_protect_window(values[0], values[1], values[2], values[3], values[4]); + if (ret) + goto error; + break; + case IRIS_BRIGHTNESS_CHIP: + iris_brightness_level_set(&values[0]); + break; + case IRIS_LCE_DEMO_WINDOW: + iris_lce_demo_window_set(values[0], values[1], values[2]); + break; + case IRIS_WAIT_VSYNC: + if (count > 2) + iris_set_pending_panel_brightness(values[0], values[1], values[2]); + break; + default: + goto error; + } + + return 0; + +error: + return -EINVAL; +error1: + return -EPERM; +} + +int iris_configure_ex(u32 display, u32 type, u32 count, u32 *values) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(display); + struct iris_cfg *pcfg1 = iris_get_cfg_by_index(DSI_PRIMARY); + int rc = 0; + + IRIS_LOGI("%s(), type: 0x%04x(%d), value: %#x(%d), count: %d, abyp mode: %d", + __func__, + type, type, values[0], values[0], count, pcfg->abypss_ctrl.abypass_mode); + if (!_iris_is_valid_type(display, type)) + return -EPERM; + + switch (type) { + case IRIS_WAIT_VSYNC: + /* don't lock panel_lock */ + return _iris_configure_ex(display, type, count, values); + } + + mutex_lock(&pcfg1->panel->panel_lock); + rc = _iris_configure_ex(display, type, count, values); + mutex_unlock(&pcfg1->panel->panel_lock); + return rc; +} + +static int iris_configure_ex_t(uint32_t display, uint32_t type, + uint32_t count, void __user *values) +{ + int ret = -1; + uint32_t *val = NULL; + + val = vmalloc(sizeof(uint32_t) * count); + if (!val) { + IRIS_LOGE("can not vmalloc space"); + return -ENOSPC; + } + ret = copy_from_user(val, values, sizeof(uint32_t) * count); + if (ret) { + IRIS_LOGE("can not copy from user"); + vfree(val); + return -EPERM; + } + ret = iris_configure_ex(display, type, count, val); + vfree(val); + return ret; +} + +int iris_configure_get(u32 display, u32 type, u32 count, u32 *values) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(display); + struct iris_cfg *pcfg1 = iris_get_cfg_by_index(DSI_PRIMARY); + struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + struct iris_setting_info *iris_setting = iris_get_setting(); + struct quality_setting *pqlt_cur_setting = &iris_setting->quality_cur; + u32 reg_addr, reg_val; + + if (type >= IRIS_CONFIG_TYPE_MAX) + return -EINVAL; + + switch (type) { + case IRIS_PEAKING: + *values = pqlt_cur_setting->pq_setting.peaking; + break; + case IRIS_CM_6AXES: + *values = pqlt_cur_setting->pq_setting.cm6axis; + break; + case IRIS_CM_FTC_ENABLE: + *values = pqlt_cur_setting->cmftc; + break; + case IRIS_S_CURVE: + *values = pqlt_cur_setting->scurvelevel; + break; + case IRIS_CM_COLOR_TEMP_MODE: + *values = pqlt_cur_setting->pq_setting.cmcolortempmode; + break; + case IRIS_CM_COLOR_GAMUT: + *values = pqlt_cur_setting->pq_setting.cmcolorgamut; + break; + case IRIS_LCE_MODE: + *values = pqlt_cur_setting->pq_setting.lcemode; + break; + case IRIS_LCE_LEVEL: + *values = pqlt_cur_setting->pq_setting.lcelevel; + break; + case IRIS_GRAPHIC_DET_ENABLE: + *values = pqlt_cur_setting->pq_setting.graphicdet; + break; + case IRIS_AL_ENABLE: + *values = pqlt_cur_setting->pq_setting.alenable; + break; + case IRIS_DBC_LEVEL: + *values = pqlt_cur_setting->pq_setting.dbc; + break; + case IRIS_DEMO_MODE: + *values = pqlt_cur_setting->pq_setting.demomode; + break; + case IRIS_SDR2HDR: + *values = pqlt_cur_setting->pq_setting.sdr2hdr; + break; + case IRIS_LUX_VALUE: + *values = pqlt_cur_setting->luxvalue; + break; + case IRIS_READING_MODE: + *values = pqlt_cur_setting->pq_setting.readingmode; + break; + case IRIS_DYNAMIC_POWER_CTRL: + *values = iris_dynamic_power_get(); + break; + case IRIS_HDR_MAXCLL: + *values = pqlt_cur_setting->maxcll; + break; + case IRIS_ANALOG_BYPASS_MODE: + *values = pcfg->abypss_ctrl.abypass_mode; + break; + case IRIS_DBG_LOOP_BACK_MODE: + *values = pcfg->loop_back_mode; + break; + case IRIS_DBG_LOOP_BACK_MODE_RES: + *values = pcfg->loop_back_mode_res; + break; + case IRIS_CM_COLOR_GAMUT_PRE: + *values = pqlt_cur_setting->source_switch; + break; + case IRIS_CCT_VALUE: + *values = pqlt_cur_setting->cctvalue; + break; + case IRIS_COLOR_TEMP_VALUE: + *values = pqlt_cur_setting->colortempvalue; + break; + case IRIS_CHIP_VERSION: + if (*values == 1) + *values = pcfg1->chip_value[1]; + else { + *values = 0; + if (iris_is_chip_supported()) + *values |= (1 << IRIS5_VER); + if (iris_is_softiris_supported()) + *values |= (1 << IRISSOFT_VER); + if (iris_is_dual_supported()) + *values |= (1 << IRIS5DUAL_VER); + if (*values == 0) + return -EFAULT; + } + break; + case IRIS_PANEL_TYPE: + *values = pcfg->panel_type; + break; + case IRIS_PANEL_NITS: + *values = pcfg->panel_nits; + break; + case IRIS_MCF_DATA: + mutex_lock(&pcfg1->panel->panel_lock); + /* get MCF from panel */ + mutex_unlock(&pcfg1->panel->panel_lock); + break; + case IRIS_DBG_TARGET_REGADDR_VALUE_GET: + IRIS_LOGI("%s:%d, pcfg->abypss_ctrl.abypass_mode = %d", + __func__, __LINE__, + pcfg->abypss_ctrl.abypass_mode); + if ((pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) && (adb_type == 0)) + return -ENOTCONN; + + if (adb_type == 0) { + mutex_lock(&pcfg1->panel->panel_lock); + iris_set_cfg_index(DSI_PRIMARY); + *values = iris_ocp_read(*values, DSI_CMD_SET_STATE_HS); + mutex_unlock(&pcfg1->panel->panel_lock); + } else if (adb_type == 1) { + reg_addr = *values; + if (iris_i2c_ver == 0) { + if (pcfg->iris_i2c_read) { + if (pcfg->iris_i2c_read(reg_addr, ®_val) < 0) + IRIS_LOGE("i2c read reg fails, reg=0x%x", reg_addr); + else + *values = reg_val; + } else { + IRIS_LOGE("Game Station is not connected"); + } + } else { + iris_i2c_ocp_read(values, 1, 0); + IRIS_LOGD("addr = %x, value = %x\n", reg_addr, *values); + } + } + break; + case IRIS_DBG_KERNEL_LOG_LEVEL: + *values = iris_get_loglevel(); + break; + case IRIS_VIDEO_FRAME_RATE_SET: + *values = (u32)pcfg->frc_setting.in_fps * 1000; + break; + case IRIS_OUT_FRAME_RATE_SET: + *values = pcfg->frc_setting.out_fps; + break; + case IRIS_OSD_ENABLE: + *values = pcfg->osd_on ? 1 : 0; + break; + case IRIS_OSD_AUTOREFRESH: + // Always use secondary display. + pcfg = iris_get_cfg_by_index(DSI_SECONDARY); + *values = pcfg->iris_osd_autorefresh ? 1 : 0; + break; + case IRIS_OSD_OVERFLOW_ST: + // Always use secondary display. + *values = iris_get_osd_overflow_st(); + break; + case IRIS_MIPI2RX_PWRST: + pcfg = iris_get_cfg_by_index(DSI_SECONDARY); + *values = pcfg->mipi_pwr_st; + break; + case IRIS_DUAL2SINGLE_ST: + mutex_lock(&pcfg1->panel->panel_lock); + if (pcfg2->mipi_pwr_st == false) { + IRIS_LOGI("mipi2 rx has been power off"); + *values = 1; + } else + *values = iris_get_dual2single_status(); + mutex_unlock(&pcfg1->panel->panel_lock); + break; + case IRIS_WORK_MODE: + *values = ((int)pcfg->pwil_mode<<16) | ((int)pcfg->tx_mode<<8) | ((int)pcfg->rx_mode); + break; + case IRIS_PANEL_TE: + *values = pcfg1->panel_te; + break; + case IRIS_AP_TE: + *values = pcfg1->ap_te; + IRIS_LOGI("get IRIS_AP_TE: %d", pcfg1->ap_te); + break; + case IRIS_MODE_SET: + mutex_lock(&pcfg1->panel->panel_lock); + iris_set_cfg_index(DSI_PRIMARY); + *values = iris_mode_switch_update(); + mutex_unlock(&pcfg1->panel->panel_lock); + break; + case IRIS_N2M_ENABLE: + *values = pcfg1->n2m_enable; + break; + case IRIS_MEMC_LEVEL: + *values = pcfg1->frc_setting.memc_level; + break; + case IRIS_MEMC_OSD: + *values = pcfg1->frc_setting.memc_osd; + break; + case IRIS_PARAM_VALID: + *values = pcfg1->valid; + break; + default: + return -EFAULT; + } + + IRIS_LOGI("%s(), type: 0x%04x(%d), value: %d", + __func__, + type, type, *values); + return 0; +} + +int iris_configure_get_t(uint32_t display, uint32_t type, + uint32_t count, void __user *values) +{ + int ret = -1; + uint32_t *val = NULL; + + val = vmalloc(count * sizeof(uint32_t)); + if (val == NULL) { + IRIS_LOGE("could not vmalloc space for func = %s", __func__); + return -ENOSPC; + } + ret = copy_from_user(val, values, sizeof(uint32_t) * count); + if (ret) { + IRIS_LOGE("can not copy from user"); + vfree(val); + return -EPERM; + } + ret = iris_configure_get(display, type, count, val); + if (ret) { + IRIS_LOGE("get error"); + vfree(val); + return ret; + } + ret = copy_to_user(values, val, sizeof(uint32_t) * count); + if (ret) { + IRIS_LOGE("copy to user error"); + vfree(val); + return -EPERM; + } + vfree(val); + return ret; +} + +int iris_operate_conf(struct msm_iris_operate_value *argp) +{ + int ret = -1; + uint32_t parent_type = 0; + uint32_t child_type = 0; + uint32_t display_type = 0; + struct iris_cfg *pcfg = NULL; + + IRIS_LOGD("%s type=0x%04x", __func__, argp->type); + + parent_type = argp->type & 0xff; + child_type = (argp->type >> 8) & 0xff; + display_type = (argp->type >> 16) & 0xff; + pcfg = iris_get_cfg_by_index(display_type); + if (pcfg == NULL || pcfg->valid < PARAM_PARSED) { + if (child_type == IRIS_WAIT_VSYNC || child_type == IRIS_CHIP_VERSION) + IRIS_LOGV("Allow type 0x%04x(%u) for Soft Iris", child_type, child_type); + else { + IRIS_LOGE("Target display does not exist!"); + return -EPERM; + } + } + + switch (parent_type) { + case IRIS_OPRT_CONFIGURE: + ret = iris_configure_t(display_type, child_type, argp->values); + break; + case IRIS_OPRT_CONFIGURE_NEW: + ret = iris_configure_ex_t(display_type, child_type, argp->count, argp->values); + break; + case IRIS_OPRT_CONFIGURE_NEW_GET: + ret = iris_configure_get_t(display_type, child_type, argp->count, argp->values); + break; + default: + IRIS_LOGE("could not find right operate type = %d", argp->type); + break; + } + + return ret; +} + +static ssize_t iris_adb_type_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + int tot = 0; + char bp[512]; + + if (*ppos) + return 0; + + tot = scnprintf(bp, sizeof(bp), "%d\n", adb_type); + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + *ppos += tot; + + return tot; +} + +static ssize_t iris_adb_type_write(struct file *file, + const char __user *buff, size_t count, loff_t *ppos) +{ + unsigned long val; + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + adb_type = val; + + return count; +} + +static const struct file_operations iris_adb_type_write_fops = { + .open = simple_open, + .write = iris_adb_type_write, + .read = iris_adb_type_read, +}; + +int iris_dbgfs_adb_type_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (debugfs_create_file("adb_type", 0644, pcfg->dbg_root, display, + &iris_adb_type_write_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + return 0; +} + +/* Iris log level definition, for 'dsi_iris5_log.h' */ +static int iris_log_level = 2; + +void iris_set_loglevel(int level) +{ + iris_log_level = level; +} + +inline int iris_get_loglevel(void) +{ + return iris_log_level; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.h b/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.h new file mode 100755 index 000000000000..8c065b76da8c --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_ioctl.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_IOCTL_H_ +#define _DSI_IRIS_IOCTL_H_ + +int iris_configure(u32 display, u32 type, u32 value); +int iris_configure_ex(u32 display, u32 type, u32 count, u32 *values); +int iris_configure_get(u32 display, u32 type, u32 count, u32 *values); +int iris_dbgfs_adb_type_init(struct dsi_display *display); + +#endif // _DSI_IRIS_IOCTL_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lightup.c b/techpack/display/msm/dsi/iris/dsi_iris5_lightup.c new file mode 100755 index 000000000000..6cb39ba2f1a9 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lightup.c @@ -0,0 +1,3739 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <drm/drm_mipi_dsi.h> +#include <video/mipi_display.h> +#include <dsi_drm.h> +#include <sde_encoder_phys.h> +#include <sde_trace.h> +#include "dsi_parser.h" +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_ioctl.h" +#include "dsi_iris5_lut.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_loop_back.h" +#include "dsi_iris5_gpio.h" +#include "dsi_iris5_frc.h" +#include "dsi_iris5_timing_switch.h" +#include "dsi_iris5_log.h" + +//#define IRIS_HDK_DEV +#define IRIS_CHIP_VER_0 0 +#define IRIS_CHIP_VER_1 1 +#define IRIS_OCP_HEADER_ADDR_LEN 8 + +#define to_dsi_display(x) container_of(x, struct dsi_display, host) + +enum { + DSI_CMD_ONE_LAST_FOR_MULT_IPOPT = 0, + DSI_CMD_ONE_LAST_FOR_ONE_IPOPT, + DSI_CMD_ONE_LAST_FOR_ONE_PKT, +}; + +/*use to parse dtsi cmd list*/ +struct iris_cmd_header { + uint32_t dsi_type; /* dsi command type 0x23 0x29*/ + uint32_t last_pkt; /*last in chain*/ + uint32_t wait_us; /*wait time*/ + uint32_t ip_type; /*ip type*/ + uint32_t opt_and_link; /*ip option and lp or hs*/ + uint32_t payload_len; /*payload len*/ +}; + +struct iris_cmd_comp { + int32_t link_state; + int32_t cnt; + struct dsi_cmd_desc *cmd; +}; + +static int gcfg_index; +static struct iris_cfg gcfg[IRIS_CFG_NUM] = {}; +static uint8_t g_cont_splash_type = IRIS_CONT_SPLASH_NONE; +uint8_t iris_pq_update_path = PATH_DSI; + +int iris_dbgfs_status_init(struct dsi_display *display); +static int _iris_dbgfs_cont_splash_init(struct dsi_display *display); +static void _iris_send_cont_splash_pkt(uint32_t type); +static int _iris_update_pq_seq(struct iris_update_ipopt *popt, int len); + +static int _iris_get_vreg(void) +{ + int rc = 0; + int i; + struct regulator *vreg = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + struct dsi_panel *panel = pcfg->panel; + + for (i = 0; i < pcfg->iris_power_info.count; i++) { + vreg = devm_regulator_get(panel->parent, + pcfg->iris_power_info.vregs[i].vreg_name); + rc = PTR_RET(vreg); + if (rc) { + IRIS_LOGE("failed to get %s regulator", + pcfg->iris_power_info.vregs[i].vreg_name); + goto error_put; + } + pcfg->iris_power_info.vregs[i].vreg = vreg; + } + + return rc; +error_put: + for (i = i - 1; i >= 0; i--) { + devm_regulator_put(pcfg->iris_power_info.vregs[i].vreg); + pcfg->iris_power_info.vregs[i].vreg = NULL; + } + return rc; +} + +static int _iris_put_vreg(void) +{ + int rc = 0; + int i; + struct iris_cfg *pcfg = iris_get_cfg(); + + for (i = pcfg->iris_power_info.count - 1; i >= 0; i--) + devm_regulator_put(pcfg->iris_power_info.vregs[i].vreg); + + return rc; +} + +void iris_init(struct dsi_display *display, struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGI("%s(), for dispaly: %s, panel: %s, cfg index: %d", + __func__, + display->display_type, panel->name, gcfg_index); + pcfg->display = display; + pcfg->panel = panel; + pcfg->iris_i2c_read = NULL; + pcfg->iris_i2c_write = NULL; + pcfg->lp_ctrl.esd_enable = true; + pcfg->aod = false; + pcfg->fod = false; + pcfg->fod_pending = false; + atomic_set(&pcfg->fod_cnt, 0); + pcfg->iris_initialized = false; + iris_init_timing_switch(); +#ifdef IRIS_ABYP_LIGHTUP + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; +#else + // UEFI is running bypass mode. + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + + if (iris_virtual_display(display)) + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + else if (pcfg->valid < PARAM_PARSED) + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + else + iris_init_vfr_work(pcfg); +#endif + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + mutex_init(&pcfg->abypss_ctrl.abypass_mutex); + +#ifndef IRIS_HDK_DEV // skip ext clk + pcfg->ext_clk = devm_clk_get(&display->pdev->dev, "pw_bb_clk2"); +#endif + + if (!iris_virtual_display(display) && pcfg->valid >= PARAM_PARSED) { + pcfg->cmd_list_index = IRIS_DTSI0_PIP_IDX; + pcfg->cur_fps_in_iris = LOW_FREQ; + pcfg->next_fps_for_iris = LOW_FREQ; + pcfg->cur_vres_in_iris = FHD_H; + iris_dbgfs_lp_init(display); + iris_dbgfs_pq_init(display); + _iris_dbgfs_cont_splash_init(display); + iris_loop_back_init(display); + iris_dbgfs_ms_init(display); + iris_dbgfs_adb_type_init(display); + iris_dbgfs_fw_calibrate_status_init(); + iris_dbgfs_frc_init(); + iris_dbgfs_status_init(display); + iris_dbg_gpio_init(); + } + _iris_get_vreg(); + //pcfg->mipi_pwr_st = true; //force to true for aux ch at boot up to workaround + mutex_init(&pcfg->gs_mutex); +} + +void iris_deinit(struct dsi_display *display) +{ + struct iris_cfg *pcfg; + int i; + + if (!iris_is_chip_supported()) + return; + + if (iris_virtual_display(display)) + pcfg = iris_get_cfg_by_index(DSI_SECONDARY); + else + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + +#ifndef IRIS_HDK_DEV // skip ext clk + if (pcfg->ext_clk) { + devm_clk_put(&display->pdev->dev, pcfg->ext_clk); + pcfg->ext_clk = NULL; + } +#endif + + for (i = 0; i < IRIS_PIP_IDX_CNT; i++) + iris_free_ipopt_buf(i); + _iris_put_vreg(); +} + +void iris_control_pwr_regulator(bool on) +{ + int rc = 0; + struct iris_cfg *pcfg = NULL; + + if (!iris_is_chip_supported()) + return; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + rc = dsi_pwr_enable_regulator(&pcfg->iris_power_info, on); + if (rc) + IRIS_LOGE("failed to power %s iris", on ? "on" : "off"); +} + +void iris_power_on(struct dsi_panel *panel) +{ + if (!iris_is_chip_supported()) + return; + + IRIS_LOGI("%s(), for [%s] %s, cfg index: %i, secondary: %s", + __func__, + panel->name, panel->type, gcfg_index, + panel->is_secondary ? "true" : "false"); + + if (panel->is_secondary) + return; + +#ifdef IRIS_HDK_DEV // skip power control + return; +#endif + + if (iris_vdd_valid()) { + iris_enable_vdd(); + } else { // No need to control vdd and clk + IRIS_LOGW("%s(), vdd does not valid, use pmic", __func__); + iris_control_pwr_regulator(true); + } + + usleep_range(5000, 5000); +} + +void iris_reset(void) +{ +#ifndef IRIS_HDK_DEV // skip ext clk + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); +#endif + + if (!iris_is_chip_supported()) + return; + + IRIS_LOGI("%s()", __func__); + +#ifndef IRIS_HDK_DEV // skip ext clk + if (pcfg->ext_clk) { + IRIS_LOGI("%s(), enable ext clk", __func__); + clk_prepare_enable(pcfg->ext_clk); + usleep_range(5000, 5001); + } else { // No need to control vdd and clk + IRIS_LOGV("%s(), invalid ext clk", __func__); + goto ERROR_CLK; + } +#endif + + iris_reset_chip(); + return; + +#ifndef IRIS_HDK_DEV // skip ext clk +ERROR_CLK: + iris_control_pwr_regulator(false); +#endif +} + +void iris_power_off(struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!iris_is_chip_supported()) + return; + + IRIS_LOGI("%s(), for [%s] %s, cfg index: %i, secondary: %s", + __func__, + panel->name, panel->type, gcfg_index, + panel->is_secondary ? "true" : "false"); + + if (panel->is_secondary) + return; + + iris_reset_off(); +#ifdef IRIS_HDK_DEV // skip power control + return; +#endif + + if (iris_vdd_valid()) + iris_disable_vdd(); + else + iris_control_pwr_regulator(false); + + if (pcfg->ext_clk) { + IRIS_LOGI("%s(), disable ext clk", __func__); + clk_disable_unprepare(pcfg->ext_clk); + } + iris_reset_off(); +} + +void iris_set_cfg_index(int index) +{ + if (index >= IRIS_CFG_NUM) { + IRIS_LOGE("%s(), index: %d exceed %d", __func__, index, IRIS_CFG_NUM); + return; + } + + IRIS_LOGD("%s(), index: %d", __func__, index); + gcfg_index = index; +} + +bool iris_virtual_display(const struct dsi_display *display) +{ + if (display && display->panel && display->panel->is_secondary) + return true; + + return false; +} + +bool iris_is_virtual_encoder_phys(void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + + if (phys_encoder == NULL) + return false; + + if (phys_encoder->connector == NULL) + return false; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return false; + + display = c_conn->display; + if (display == NULL) + return false; + + if (!iris_virtual_display(display)) + return false; + + return true; +} + +struct iris_cfg *iris_get_cfg(void) +{ + return &gcfg[gcfg_index]; +} + +struct iris_cfg *iris_get_cfg_by_index(int index) +{ + if (index < IRIS_CFG_NUM) + return &gcfg[index]; + + return NULL; +} + +uint8_t iris_get_cont_splash_type(void) +{ + return g_cont_splash_type; +} + +static struct iris_ctrl_seq *_iris_get_ctrl_seq_addr( + struct iris_ctrl_seq *base, uint8_t chip_id) +{ + struct iris_ctrl_seq *pseq = NULL; + + switch (chip_id) { + case IRIS_CHIP_VER_0: + pseq = base; + break; + case IRIS_CHIP_VER_1: + pseq = base + 1; + break; + default: + IRIS_LOGE("unknown chip id: %d", chip_id); + break; + } + return pseq; +} + +static bool _iris_is_valid_ip(uint32_t ip) +{ + if (ip >= LUT_IP_START && ip < LUT_IP_END) + return true; + + if (ip < IRIS_IP_END) //CID99843 + return true; + + return false; +} + +static struct iris_ctrl_seq *_iris_get_ctrl_seq_common( + struct iris_cfg *pcfg, int32_t type) +{ + struct iris_ctrl_seq *pseq = NULL; + + if (type == IRIS_CONT_SPLASH_NONE) + pseq = _iris_get_ctrl_seq_addr(pcfg->ctrl_seq, pcfg->chip_id); + else if (type == IRIS_CONT_SPLASH_LK) + pseq = _iris_get_ctrl_seq_addr(pcfg->ctrl_seq_cs, pcfg->chip_id); + + return pseq; +} + +static struct iris_ctrl_seq *_iris_get_ctrl_seq(struct iris_cfg *pcfg) +{ + return _iris_get_ctrl_seq_common(pcfg, IRIS_CONT_SPLASH_NONE); +} + +static struct iris_ctrl_seq *_iris_get_ctrl_seq_cs(struct iris_cfg *pcfg) +{ + return _iris_get_ctrl_seq_common(pcfg, IRIS_CONT_SPLASH_LK); +} + +static bool _iris_is_lut(uint8_t ip) +{ + return ip >= LUT_IP_START ? true : false; +} + +static uint32_t _iris_get_ocp_type(const uint8_t *payload) +{ + uint32_t *pval = (uint32_t *)payload; + + return cpu_to_le32(pval[0]); +} + +static uint32_t _iris_get_ocp_base_addr(const uint8_t *payload) +{ + uint32_t *pval = (uint32_t *)payload; + + return cpu_to_le32(pval[1]); +} + +static void _iris_set_ocp_type(const uint8_t *payload, uint32_t val) +{ + uint32_t *pval = (uint32_t *)payload; + + IRIS_LOGV("%s(), change addr from %#x to %#x.", __func__, pval[0], val); + pval[0] = val; +} + +static void _iris_set_ocp_base_addr(const uint8_t *payload, uint32_t val) +{ + uint32_t *pval = (uint32_t *)payload; + + IRIS_LOGV("%s(), change addr from %#x to %#x.", __func__, pval[1], val); + pval[1] = val; +} + +static bool _iris_is_direct_bus(const uint8_t *payload) +{ + uint8_t val = _iris_get_ocp_type(payload) & 0x0f; + + //the last 4bit will show the ocp type + if (val == 0x00 || val == 0x0c) + return true; + + return false; +} + +static int _iris_split_mult_pkt(const uint8_t *payload, int payload_size) +{ + uint32_t pkt_size = 0; + int pkt_cnt = 1; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (!_iris_is_direct_bus(payload)) + return pkt_cnt; + + pkt_size = pcfg->split_pkt_size; + if (payload_size > pkt_size + IRIS_OCP_HEADER_ADDR_LEN) + pkt_cnt = (payload_size - IRIS_OCP_HEADER_ADDR_LEN + pkt_size - 1) / pkt_size; + + return pkt_cnt; +} + +static void _iris_set_cont_splash_type(uint8_t type) +{ + g_cont_splash_type = type; +} + +struct iris_ip_index *iris_get_ip_idx(int32_t type) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (unlikely(type < IRIS_DTSI0_PIP_IDX || type >= IRIS_PIP_IDX_CNT)) { + IRIS_LOGE("%s, can not get pip idx %u", __func__, type); + return NULL; + } + + return pcfg->ip_index_arr[type]; +} + +static int32_t _iris_get_ip_idx_type(const struct iris_ip_index *pip_index) +{ + int32_t type = -1; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pip_index == pcfg->ip_index_arr[IRIS_DTSI0_PIP_IDX]) + type = IRIS_DTSI0_PIP_IDX; + else if (pip_index == pcfg->ip_index_arr[IRIS_DTSI1_PIP_IDX]) + type = IRIS_DTSI1_PIP_IDX; + else if (pip_index == pcfg->ip_index_arr[IRIS_LUT_PIP_IDX]) + type = IRIS_LUT_PIP_IDX; + + return type; +} + +static void _iris_init_ip_index(struct iris_ip_index *pip_index) +{ + int32_t i = 0; + int32_t j = 0; + int32_t cnt = 0; + int32_t ip_cnt = IRIS_IP_CNT; + + if (_iris_get_ip_idx_type(pip_index) == IRIS_LUT_PIP_IDX) + ip_cnt = LUT_IP_END - LUT_IP_START; + + for (i = 0; i < ip_cnt; i++) { + cnt = pip_index[i].opt_cnt; + for (j = 0; j < cnt; j++) { + pip_index[i].opt[j].cmd = NULL; + pip_index[i].opt[j].link_state = 0xff; + } + } +} + +static int32_t _iris_alloc_pip_buf(struct iris_ip_index *pip_index) +{ + int i = 0; + int j = 0; + int opt_cnt = 0; + int ip_cnt = IRIS_IP_CNT; + + if (_iris_get_ip_idx_type(pip_index) == IRIS_LUT_PIP_IDX) + ip_cnt = LUT_IP_END - LUT_IP_START; + + for (i = 0; i < ip_cnt; i++) { + opt_cnt = pip_index[i].opt_cnt; + if (opt_cnt != 0) { + pip_index[i].opt = + kvzalloc(opt_cnt * sizeof(struct iris_ip_opt), + GFP_KERNEL); + if (!pip_index[i].opt) { + IRIS_LOGE("%s:%d no space\n", __func__, __LINE__); + /*free already malloc space*/ + for (j = 0; j < i; j++) { + kvfree(pip_index[j].opt); + pip_index[j].opt = NULL; + } + return -ENOMEM; + } + } + } + + return 0; +} + +static int32_t _iris_alloc_desc_buf(struct dsi_cmd_desc **cmds, int cmd_cnt) +{ + int cmd_size = 0; + + /*create dsi cmds*/ + if (cmd_cnt == 0) { + IRIS_LOGE("%s(), invalid statics count", __func__); + return -EINVAL; + } + + cmd_size = cmd_cnt * sizeof(struct dsi_cmd_desc); + *cmds = vzalloc(cmd_size); + if (!(*cmds)) { + IRIS_LOGE("%s(), failed to malloc space for dsi", __func__); + return -ENOMEM; + } + IRIS_LOGI("%s(), alloc %p, count %d", __func__, *cmds, cmd_cnt); + + return 0; +} + +static int32_t _iris_alloc_cmd_buf(struct dsi_cmd_desc **cmds, + struct iris_ip_index *pip_index, int cmd_cnt) +{ + int32_t rc = 0; + + rc = _iris_alloc_desc_buf(cmds, cmd_cnt); + if (rc) + return rc; + + rc = _iris_alloc_pip_buf(pip_index); + if (rc) { + vfree(*cmds); + *cmds = NULL; + } + + return rc; +} + +static int32_t _iris_write_ip_opt(struct dsi_cmd_desc *cmd, + const struct iris_cmd_header *hdr, int32_t pkt_cnt, + struct iris_ip_index *pip_index) +{ + uint8_t i = 0; + uint8_t ip = 0; + uint8_t opt_id = 0; + uint8_t cnt = 0; + + if (!hdr || !cmd || !pip_index) { + IRIS_LOGE("%s(), invalid input parameter.", __func__); + return -EINVAL; + } + + ip = hdr->ip_type & 0xff; + opt_id = hdr->opt_and_link & 0xff; + + if (ip >= LUT_IP_START) + ip -= LUT_IP_START; + + cnt = pip_index[ip].opt_cnt; + + for (i = 0; i < cnt; i++) { + if (pip_index[ip].opt[i].cmd == NULL) { + pip_index[ip].opt[i].cmd = cmd; + pip_index[ip].opt[i].cmd_cnt = pkt_cnt; + pip_index[ip].opt[i].opt_id = opt_id; + break; + } else if (pip_index[ip].opt[i].opt_id == opt_id) { + /*find the right opt_id*/ + pip_index[ip].opt[i].cmd_cnt += pkt_cnt; + break; + } + } + + if (i == cnt) { + IRIS_LOGE("%s(), find ip opt fail, ip = 0x%02x opt = 0x%02x.", + __func__, ip, opt_id); + return -EINVAL; + } + + /*to set link state*/ + if (pip_index[ip].opt[i].link_state == 0xff + && pip_index[ip].opt[i].opt_id == opt_id) { + uint8_t link_state = 0; + + link_state = (hdr->opt_and_link >> 8) & 0xff; + pip_index[ip].opt[i].link_state = + link_state ? DSI_CMD_SET_STATE_LP : DSI_CMD_SET_STATE_HS; + } + + return 0; +} + +static int32_t _iris_trans_section_hdr_to_desc( + struct dsi_cmd_desc *cmd, const struct iris_cmd_header *hdr) +{ + memset(cmd, 0, sizeof(struct dsi_cmd_desc)); + + cmd->msg.type = (hdr->dsi_type & 0xff); + cmd->post_wait_ms = (hdr->wait_us & 0xff); + cmd->last_command = ((hdr->last_pkt & 0xff) != 0); + cmd->msg.tx_len = hdr->payload_len; + + IRIS_LOGV("%s(), type: %#x, wait: %#x, last: %s, len: %zu", + __func__, + cmd->msg.type, cmd->post_wait_ms, + cmd->last_command ? "true" : "false", cmd->msg.tx_len); + + return cmd->msg.tx_len; +} + +static void _iris_change_last_and_size(struct iris_cmd_header *dest, + const struct iris_cmd_header *src, int index, const int pkt_cnt) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int pkt_size = pcfg->split_pkt_size; + + memcpy(dest, src, sizeof(*src)); + if (index == pkt_cnt - 1) { + dest->payload_len = src->payload_len * sizeof(uint32_t) - (pkt_cnt - 1) * pkt_size; + return; + } + + dest->last_pkt = (pcfg->add_last_flag) ? 1 : 0; + dest->payload_len = (pkt_size + IRIS_OCP_HEADER_ADDR_LEN); +} + +static int _iris_write_cmd_hdr(struct dsi_cmd_desc *cmd, + const struct iris_cmd_header *phdr, int pkt_cnt) +{ + int i = 0; + struct iris_cmd_header tmp_hdr; + + for (i = 0; i < pkt_cnt; i++) { + _iris_change_last_and_size(&tmp_hdr, phdr, i, pkt_cnt); + + /*add cmds hdr information*/ + _iris_trans_section_hdr_to_desc(cmd + i, &tmp_hdr); + } + + return 0; +} + +static bool _iris_need_direct_send(const struct iris_cmd_header *hdr) +{ + if (hdr == NULL) { + IRIS_LOGE("%s(), invalid input!", __func__); + return false; + } + + if (hdr->ip_type == APP_CODE_LUT) + return true; + + return false; +} + +static void _iris_create_cmd_payload(const struct iris_cmd_header *hdr, + const uint8_t *payload, uint8_t *msg_buf, int32_t buf_size) +{ + int32_t i = 0; + uint32_t *pval = NULL; + uint32_t cnt = 0; + + if (_iris_need_direct_send(hdr)) { + memcpy(msg_buf, payload, buf_size); + return; + } + + pval = (uint32_t *)payload; + cnt = buf_size >> 2; + for (i = 0; i < cnt; i++) + *(uint32_t *)(msg_buf + (i << 2)) = cpu_to_le32(pval[i]); +} + +static int _iris_write_cmd_payload(struct dsi_cmd_desc *pdesc, + const struct iris_cmd_header *hdr, const char *payload, int pkt_cnt) +{ + int i = 0; + uint32_t dlen = 0; + uint8_t *ptr = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + uint32_t pkt_size = pcfg->split_pkt_size; + uint32_t ocp_type = _iris_get_ocp_type(payload); + uint32_t base_addr = _iris_get_ocp_base_addr(payload); + + if (pkt_cnt == 1) { + dlen = pdesc->msg.tx_len; + ptr = vzalloc(dlen); + if (!ptr) { + IRIS_LOGE("%s Failed to allocate memory", __func__); + return -ENOMEM; + } + + _iris_create_cmd_payload(hdr, payload, ptr, dlen); + pdesc->msg.tx_buf = ptr; + } else { + /*remove header and base address*/ + payload += IRIS_OCP_HEADER_ADDR_LEN; + for (i = 0; i < pkt_cnt; i++) { + dlen = pdesc[i].msg.tx_len; + + ptr = vzalloc(dlen); + if (!ptr) { + IRIS_LOGE("can not allocate space"); + return -ENOMEM; + } + + _iris_set_ocp_base_addr(ptr, base_addr + i * pkt_size); + _iris_set_ocp_type(ptr, ocp_type); + _iris_create_cmd_payload(hdr, payload, + ptr + IRIS_OCP_HEADER_ADDR_LEN, + dlen - IRIS_OCP_HEADER_ADDR_LEN); + + /* add payload */ + payload += (dlen - IRIS_OCP_HEADER_ADDR_LEN); + pdesc[i].msg.tx_buf = ptr; + } + } + + if (IRIS_IF_LOGVV()) { + int len = 0; + + for (i = 0; i < pkt_cnt; i++) { + len = (pdesc[i].msg.tx_len > 16) ? 16 : pdesc[i].msg.tx_len; + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, + pdesc[i].msg.tx_buf, len, false); + } + } + + return 0; +} + +void iris_change_type_addr(struct iris_ip_opt *dest, struct iris_ip_opt *src) +{ + int i = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + uint32_t pkt_size = pcfg->split_pkt_size; + const void *buf = src->cmd->msg.tx_buf; + int pkt_cnt = dest->cmd_cnt; + uint32_t ocp_type = _iris_get_ocp_type(buf); + uint32_t base_addr = _iris_get_ocp_base_addr(buf); + + for (i = 0; i < pkt_cnt; i++) { + buf = dest->cmd[i].msg.tx_buf; + _iris_set_ocp_base_addr(buf, base_addr + i * pkt_size); + _iris_set_ocp_type(buf, ocp_type); + if (IRIS_LOGD_IF(i == 0)) { + IRIS_LOGD("%s(), change ocp type 0x%08x, change base addr to 0x%08x.", + __func__, ocp_type, base_addr); + } + } +} + +struct iris_ip_opt *iris_find_ip_opt(uint8_t ip, uint8_t opt_id) +{ + int32_t i = 0; + struct iris_ip_opt *popt = NULL; + struct iris_ip_index *pip_index = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + int32_t type = pcfg->cmd_list_index; + + IRIS_LOGV("%s(), ip: %#x, opt: %#x", __func__, ip, opt_id); + if (!_iris_is_valid_ip(ip)) { + IRIS_LOGE("%s(), ip %d is out of range", __func__, ip); + return NULL; + } + + if (ip >= LUT_IP_START) { + type = IRIS_LUT_PIP_IDX; + ip -= LUT_IP_START; + } + + pip_index = iris_get_ip_idx(type) + ip; + + for (i = 0; i < pip_index->opt_cnt; i++) { + popt = pip_index->opt + i; + if (popt->opt_id == opt_id) + return popt; + } + + return NULL; +} + +static void _iris_print_ipopt(struct iris_ip_index *pip_index) +{ + int32_t i = 0; + int32_t j = 0; + int32_t ip_cnt = IRIS_IP_CNT; + + if (_iris_get_ip_idx_type(pip_index) == IRIS_LUT_PIP_IDX) + ip_cnt = LUT_IP_END - LUT_IP_START; + + for (i = 0; i < ip_cnt; i++) { + for (j = 0; j < pip_index[i].opt_cnt; j++) { + struct iris_ip_opt *popt = &(pip_index[i].opt[j]); + + IRIS_LOGI("%s(%d), ip: %02x, opt: %02x, cmd: %p, len: %d, link state: %#x", + __func__, __LINE__, + i, popt->opt_id, popt->cmd, popt->cmd_cnt, popt->link_state); + } + } +} + +static void _iris_parse_appversion( + const uint8_t *payload, const struct iris_cmd_header *phdr) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + uint32_t *pval = NULL; + uint32_t app_version = 0x0; + uint32_t app_date; + + if (phdr->ip_type != APP_VERSION_LUT) + return; + + pval = (uint32_t *)payload; + + app_version = *pval; + app_date = *(pval + 1); + pcfg->app_version = app_version; + pcfg->app_date[0] = app_date & 0xff; + pcfg->app_date[1] = (app_date >> 8) & 0xff; + pcfg->app_date[2] = (app_date >> 16) & 0xff; + pcfg->app_date[3] = (app_date >> 24) & 0xff; + IRIS_LOGI("%s(), iris fw version: %d, [date]%d:%d:%d:%d", + __func__, + pcfg->app_version, + pcfg->app_date[3], + pcfg->app_date[2], + pcfg->app_date[1], + pcfg->app_date[0]); +} + +static int32_t _iris_add_cmd_to_ipidx(const struct iris_data *data, + struct dsi_cmd_desc *cmds, int cmd_pos, struct iris_ip_index *pip_index) +{ + int32_t span = 0; + int32_t pkt_cnt = 0; + int32_t total_size = 0; + int32_t payload_size = 0; + struct dsi_cmd_desc *pdesc = NULL; + const uint8_t *payload = NULL; + const struct iris_cmd_header *hdr = NULL; + const uint8_t *buf_ptr = (uint8_t *)data->buf; + int32_t data_size = data->size; + int32_t cmd_index = cmd_pos; + + while (total_size < data_size) { + hdr = (const struct iris_cmd_header *)buf_ptr; + pdesc = &cmds[cmd_index]; + payload = buf_ptr + sizeof(struct iris_cmd_header); + payload_size = hdr->payload_len * sizeof(uint32_t); + total_size += sizeof(struct iris_cmd_header) + payload_size; + + _iris_parse_appversion(payload, hdr); + + pkt_cnt = _iris_split_mult_pkt(payload, payload_size); + if (IRIS_LOGV_IF(pkt_cnt > 1)) + IRIS_LOGV("%s(), pkt_cnt is: %d.", __func__, pkt_cnt); + + /*need to first write desc header and then write payload*/ + _iris_write_cmd_hdr(pdesc, hdr, pkt_cnt); + _iris_write_cmd_payload(pdesc, hdr, payload, pkt_cnt); + + /*write cmd link information*/ + _iris_write_ip_opt(pdesc, hdr, pkt_cnt, pip_index); + + buf_ptr += sizeof(struct iris_cmd_header) + payload_size; + cmd_index += pkt_cnt; + } + span = cmd_index - cmd_pos; + + if (IRIS_IF_LOGVV()) + _iris_print_ipopt(pip_index); + + return span; +} + +static int32_t _iris_create_ipidx(const struct iris_data *data, int32_t data_cnt, + struct iris_ip_index *pip_index, int32_t cmd_cnt) +{ + int32_t i = 0; + int32_t rc = 0; + int32_t cmd_pos = 0; + struct dsi_cmd_desc *cmds = NULL; + + /*create dsi cmd list*/ + rc = _iris_alloc_cmd_buf(&cmds, pip_index, cmd_cnt); + if (rc) { + IRIS_LOGE("create dsi memory failed!"); + return -ENOMEM; + } + + _iris_init_ip_index(pip_index); + + for (i = 0; i < data_cnt; i++) { + if (data[i].size == 0) { + IRIS_LOGW("data[%d] length is %d.", i, data[i].size); + continue; + } + cmd_pos += _iris_add_cmd_to_ipidx(&data[i], cmds, cmd_pos, pip_index); + } + + if (cmd_cnt != cmd_pos) { + IRIS_LOGE("%s(), invalid desc, cmd count: %d, cmd pos: %d.", + __func__, cmd_cnt, cmd_pos); + } + + return 0; +} + +static int32_t _iris_accum_section_desc_cnt(const struct iris_cmd_header *hdr, + const uint8_t *payload, int32_t *pcmd_cnt) +{ + int pkt_cnt = 1; + int32_t payload_size = 0; + + if (!hdr || !pcmd_cnt || !payload) { + IRIS_LOGE("%s(%d), invalid input parameter!", __func__, __LINE__); + return -EINVAL; + } + + payload_size = hdr->payload_len * sizeof(uint32_t); + pkt_cnt = _iris_split_mult_pkt(payload, payload_size); + + /* it will split to pkt_cnt dsi cmds + * add (pkt_cnt-1) ocp_header(4 bytes) and ocp_type(4 bytes) + */ + *pcmd_cnt += pkt_cnt; + + IRIS_LOGV("%s(), dsi cmd count: %d", __func__, *pcmd_cnt); + + return 0; +} + +static int32_t _iris_accum_section_opt_cnt(const struct iris_cmd_header *hdr, + struct iris_ip_index *pip_index) +{ + uint8_t last = 0; + uint8_t ip = 0; + + if (!hdr || !pip_index) { + IRIS_LOGE("%s(%d), invalid input parameter.", __func__, __LINE__); + return -EINVAL; + } + + last = hdr->last_pkt & 0xff; + ip = hdr->ip_type & 0xff; + + if (last == 1) { + if (ip >= LUT_IP_START) + ip -= LUT_IP_START; + pip_index[ip].opt_cnt++; + } + + return 0; +} + +static int32_t _iris_poll_each_section(const struct iris_cmd_header *hdr, + const char *payload, struct iris_ip_index *pip_index, int32_t *pcmd_cnt) +{ + int32_t rc = 0; + + rc = _iris_accum_section_desc_cnt(hdr, payload, pcmd_cnt); + if (rc) + goto EXIT_VAL; + + rc = _iris_accum_section_opt_cnt(hdr, pip_index); + if (rc) + goto EXIT_VAL; + + return 0; + +EXIT_VAL: + + IRIS_LOGE("%s(), cmd static is error!", __func__); + return rc; +} + +static int32_t _iris_verify_dtsi(const struct iris_cmd_header *hdr, + struct iris_ip_index *pip_index) +{ + uint32_t *pval = NULL; + uint8_t tmp = 0; + int32_t rc = 0; + int32_t type = _iris_get_ip_idx_type(pip_index); + + if (type >= IRIS_DTSI0_PIP_IDX && type <= IRIS_DTSI1_PIP_IDX) { + if (hdr->ip_type >= IRIS_IP_CNT) { + IRIS_LOGE("hdr->ip_type is 0x%0x out of max ip", hdr->ip_type); + rc = -EINVAL; + } else if (((hdr->opt_and_link >> 8) & 0xff) > 1) { + IRIS_LOGE("hdr->opt link state not right 0x%0x", hdr->opt_and_link); + rc = -EINVAL; + } + } else { + if (hdr->ip_type >= LUT_IP_END || hdr->ip_type < LUT_IP_START) { + IRIS_LOGE("hdr->ip_type is 0x%0x out of ip range", hdr->ip_type); + rc = -EINVAL; + } + } + + switch (hdr->dsi_type) { + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + break; + case MIPI_DSI_GENERIC_LONG_WRITE: + /*judge payload0 for iris header*/ + pval = (uint32_t *)hdr + (sizeof(*hdr) >> 2); + tmp = *pval & 0x0f; + if (tmp == 0x00 || tmp == 0x05 || tmp == 0x0c || tmp == 0x08) { + break; + } else if (tmp == 0x04) { + if ((hdr->payload_len - 1) % 2 != 0) { + IRIS_LOGE("dlen is not right = %d", hdr->payload_len); + rc = -EINVAL; + } + } else { + IRIS_LOGE("payload hdr is not right = %0x", *pval); + rc = -EINVAL; + } + break; + default: + IRIS_LOGE("dsi type is not right %0x", hdr->dsi_type); + rc = -EINVAL; + } + + if (rc) { + IRIS_LOGE("hdr info: %#x %#x %#x %#x %#x %#x", + hdr->dsi_type, hdr->last_pkt, + hdr->wait_us, hdr->ip_type, + hdr->opt_and_link, hdr->payload_len); + } + + return rc; +} + +static int32_t _iris_parse_panel_type( + struct device_node *np, struct iris_cfg *pcfg) +{ + const char *data = NULL; + u32 value = 0; + u8 values[2] = {}; + int32_t rc = 0; + + data = of_get_property(np, "pxlw,panel-type", NULL); + if (data) { + if (!strcmp(data, "PANEL_LCD_SRGB")) + pcfg->panel_type = PANEL_LCD_SRGB; + else if (!strcmp(data, "PANEL_LCD_P3")) + pcfg->panel_type = PANEL_LCD_P3; + else if (!strcmp(data, "PANEL_OLED")) + pcfg->panel_type = PANEL_OLED; + else/*default value is 0*/ + pcfg->panel_type = PANEL_LCD_SRGB; + } else { /*default value is 0*/ + pcfg->panel_type = PANEL_LCD_SRGB; + IRIS_LOGW("parse panel type failed!"); + } + + rc = of_property_read_u32(np, "pxlw,panel-dimming-brightness", &value); + if (rc == 0) { + pcfg->panel_dimming_brightness = value; + } else { + /* for V30 panel, 255 may cause panel during exit HDR, and lost TE.*/ + pcfg->panel_dimming_brightness = 250; + IRIS_LOGW("parse panel dimming brightness failed!"); + } + + rc = of_property_read_u8_array(np, "pxlw,panel-hbm", values, 2); + if (rc == 0) { + pcfg->panel_hbm[0] = values[0]; + pcfg->panel_hbm[1] = values[1]; + } else { + pcfg->panel_hbm[0] = 0xff; + pcfg->panel_hbm[1] = 0xff; + } + + return 0; +} + +static int32_t _iris_parse_chip_ver( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + + rc = of_property_read_u32(np, "pxlw,chip-ver", + &(pcfg->chip_ver)); + if (rc) { + IRIS_LOGE("can not get property: pxlw, chip-ver"); + return rc; + } + IRIS_LOGE("pxlw,chip-version: %#x", pcfg->chip_ver); + + return rc; +} + +static int32_t _iris_parse_lut_mode( + struct device_node *np, struct iris_cfg *pcfg) +{ + const char *data; + + data = of_get_property(np, "pxlw,lut-mode", NULL); + if (data) { + if (!strcmp(data, "single")) + pcfg->lut_mode = SINGLE_MODE; + else if (!strcmp(data, "interpolation")) + pcfg->lut_mode = INTERPOLATION_MODE; + else/*default value is 0*/ + pcfg->lut_mode = INTERPOLATION_MODE; + } else { /*default value is 0*/ + pcfg->lut_mode = INTERPOLATION_MODE; + IRIS_LOGI("no lut mode set, use default"); + } + + IRIS_LOGI("pxlw,lut-mode: %d", pcfg->lut_mode); + return 0; +} + +static int32_t _iris_parse_split_pkt_info( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + + rc = of_property_read_u32(np, "pxlw,pkt-payload-size", + &(pcfg->split_pkt_size)); + if (rc) { + IRIS_LOGE("can not get property: pxlw,pkt-payload-size"); + return rc; + } + IRIS_LOGI("pxlw,split-pkt-payload-size: %d", pcfg->split_pkt_size); + + rc = of_property_read_u32(np, "pxlw,last-for-per-pkt", + &(pcfg->add_on_last_flag)); + if (rc) { + IRIS_LOGE("can not get property:pxlw,last-for-per-pkt"); + pcfg->add_on_last_flag = DSI_CMD_ONE_LAST_FOR_ONE_PKT; + } + rc = of_property_read_u32(np, "pxlw,pt-last-for-per-pkt", + &(pcfg->add_pt_last_flag)); + if (rc) { + IRIS_LOGE("can not get property:pxlw,pt-last-for-per-pkt"); + pcfg->add_pt_last_flag = DSI_CMD_ONE_LAST_FOR_MULT_IPOPT; + } + IRIS_LOGE("pxlw,add-last-for-split-pkt: %d, pxlw,add-pt-last-for-split-pkt: %d", + pcfg->add_on_last_flag, pcfg->add_pt_last_flag); + + pcfg->add_last_flag = pcfg->add_on_last_flag; + + return rc; +} + +static int32_t _iris_poll_cmd_lists(const struct iris_data *data, int32_t data_cnt, + struct iris_ip_index *pip_index, int32_t *pcmd_cnt) +{ + int32_t rc = 0; + int32_t i = 0; + int32_t payload_size = 0; + int32_t data_len = 0; + const uint8_t *buf_ptr = NULL; + const struct iris_cmd_header *hdr = NULL; + + if (data == NULL || pip_index == NULL || pcmd_cnt == NULL) { + IRIS_LOGE("%s(), invalid input!", __func__); + return -EINVAL; + } + + for (i = 0; i < data_cnt; i++) { + if (data[i].size == 0) { + IRIS_LOGW("data length is = %d", data[i].size); + continue; + } + + buf_ptr = data[i].buf; + data_len = data[i].size; + while (data_len >= sizeof(struct iris_cmd_header)) { + hdr = (const struct iris_cmd_header *)buf_ptr; + data_len -= sizeof(struct iris_cmd_header); + if (hdr->payload_len > (data_len >> 2)) { + IRIS_LOGE("%s: length error, ip = 0x%02x opt=0x%02x, len=%d", + __func__, hdr->ip_type, hdr->opt_and_link, hdr->payload_len); + return -EINVAL; + } + + if (IRIS_IF_LOGVV()) { + rc = _iris_verify_dtsi(hdr, pip_index); + if (rc) { + IRIS_LOGE("%s(%d), verify dtis return: %d", __func__, __LINE__, rc); + return rc; + } + } + + IRIS_LOGV("hdr info, type: 0x%02x, last: 0x%02x, wait: 0x%02x, ip: 0x%02x, opt: 0x%02x, len: %d.", + hdr->dsi_type, hdr->last_pkt, hdr->wait_us, + hdr->ip_type, hdr->opt_and_link, hdr->payload_len); + + //payload + buf_ptr += sizeof(struct iris_cmd_header); + + /*change to uint8_t length*/ + //hdr->payload_len *= sizeof(uint32_t); + payload_size = hdr->payload_len * sizeof(uint32_t); + + rc = _iris_poll_each_section(hdr, buf_ptr, pip_index, pcmd_cnt); + if (rc) { + IRIS_LOGE("%s(), failed to poll section: %d, return: %d", + __func__, hdr->ip_type, rc); + return rc; + } + + buf_ptr += payload_size; + data_len -= payload_size; + } + } + + return rc; +} + +static int32_t _iris_alloc_dtsi_cmd_buf( + const struct device_node *np, const uint8_t *key, uint8_t **buf) +{ + int32_t cmd_size = 0; + int32_t cmd_len = 0; + const void *ret = NULL; + + ret = of_get_property(np, key, &cmd_len); + if (!ret) { + IRIS_LOGE("%s(), failed for parsing %s", __func__, key); + return -EINVAL; + } + + if (cmd_len % 4 != 0) { + IRIS_LOGE("lenght = %d is not multpile of 4", cmd_len); + return -EINVAL; + } + + cmd_size = sizeof(char) * cmd_len; + *buf = vzalloc(cmd_size); + if (!*buf) { + IRIS_LOGE("can not vzalloc memory"); + return -ENOMEM; + } + + return cmd_size; +} + +static int32_t _iris_write_dtsi_cmd_to_buf(const struct device_node *np, + const uint8_t *key, uint8_t **buf, int size) +{ + int32_t rc = 0; + + rc = of_property_read_u32_array(np, key, + (uint32_t *)(*buf), size >> 2); + if (rc != 0) { + IRIS_LOGE("%s(%d), read array is not right", __func__, __LINE__); + return -EINVAL; + } + + return rc; +} + +static void _iris_free_dtsi_cmd_buf(uint8_t **buf) +{ + if (*buf) { + vfree(*buf); + *buf = NULL; + } +} + +static void _iris_save_cmd_count(const struct iris_ip_index *pip_index, + const int cmd_cnt) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int32_t idx_type = _iris_get_ip_idx_type(pip_index); + + if (idx_type == IRIS_DTSI0_PIP_IDX + || idx_type == IRIS_DTSI1_PIP_IDX) { //CID101339 + if (cmd_cnt > pcfg->dtsi_cmds_cnt) + pcfg->dtsi_cmds_cnt = cmd_cnt; + return; + } + + if (idx_type == IRIS_LUT_PIP_IDX) { + pcfg->lut_cmds_cnt = cmd_cnt; + return; + } + + IRIS_LOGI("%s(), doesn't save count for type %#x pip index %p", + __func__, idx_type, pip_index); +} + +int32_t iris_attach_cmd_to_ipidx(const struct iris_data *data, + int32_t data_cnt, struct iris_ip_index *pip_index) +{ + int32_t rc = 0; + int32_t cmd_cnt = 0; + + rc = _iris_poll_cmd_lists(data, data_cnt, pip_index, &cmd_cnt); + if (rc) { + IRIS_LOGE("fail to parse dtsi/lut cmd list!"); + return rc; + } + + _iris_save_cmd_count(pip_index, cmd_cnt); + + rc = _iris_create_ipidx(data, data_cnt, pip_index, cmd_cnt); + + return rc; +} + +int32_t iris_parse_dtsi_cmd(const struct device_node *lightup_node, uint32_t cmd_index) +{ + int32_t rc = 0; + int32_t cmd_size = 0; + int32_t data_cnt = 0; + uint8_t *dtsi_buf = NULL; + struct iris_ip_index *pip_index = NULL; + struct iris_data data[1]; + const uint8_t *key = "pxlw,iris-cmd-list"; + + if (cmd_index == IRIS_DTSI1_PIP_IDX) + key = "pxlw,iris-cmd-list-1"; + memset(data, 0x00, sizeof(data)); + + // need to keep dtsi buf and release after used + cmd_size = _iris_alloc_dtsi_cmd_buf(lightup_node, key, &dtsi_buf); + if (cmd_size <= 0) { + IRIS_LOGE("can not malloc space for dtsi cmd"); + return -ENOMEM; + } + + rc = _iris_write_dtsi_cmd_to_buf(lightup_node, key, &dtsi_buf, cmd_size); + if (rc) { + IRIS_LOGE("cant not write dtsi cmd to buf"); + goto FREE_DTSI_BUF; + } + data[0].buf = dtsi_buf; + data[0].size = cmd_size; + + pip_index = iris_get_ip_idx(cmd_index); + data_cnt = ARRAY_SIZE(data); + rc = iris_attach_cmd_to_ipidx(data, data_cnt, pip_index); + +FREE_DTSI_BUF: + _iris_free_dtsi_cmd_buf(&dtsi_buf); + + return rc; +} + +static void _iris_add_cmd_seq(struct iris_ctrl_opt *ctrl_opt, + int item_cnt, const uint8_t *pdata) +{ + int32_t i = 0; + uint8_t ip = 0; + uint8_t opt_id = 0; + uint8_t skip_last = 0; + const int32_t span = 3; + + for (i = 0; i < item_cnt; i++) { + ip = pdata[span * i]; + opt_id = pdata[span * i + 1]; + skip_last = pdata[span * i + 2]; + + ctrl_opt[i].ip = ip & 0xff; + ctrl_opt[i].opt_id = opt_id & 0xff; + ctrl_opt[i].skip_last = skip_last & 0xff; + + if (IRIS_IF_LOGV()) { + IRIS_LOGE("ip = %d opt = %d skip=%d", + ip, opt_id, skip_last); + } + } +} + +static int32_t _iris_alloc_cmd_seq( + struct iris_ctrl_seq *pctrl_seq, int32_t seq_cnt) +{ + pctrl_seq->ctrl_opt = vmalloc(seq_cnt * sizeof(struct iris_ctrl_seq)); + if (pctrl_seq->ctrl_opt == NULL) { + IRIS_LOGE("can not malloc space for pctrl opt"); + return -ENOMEM; + } + pctrl_seq->cnt = seq_cnt; + + return 0; +} + +static int32_t _iris_parse_cmd_seq_data(struct device_node *np, + const uint8_t *key, const uint8_t **pval) +{ + const uint8_t *pdata = NULL; + int32_t item_cnt = 0; + int32_t seq_cnt = 0; + int32_t span = 3; + + pdata = of_get_property(np, key, &item_cnt); + if (!pdata) { + IRIS_LOGE("%s %s is error", __func__, key); + return -EINVAL; + } + + seq_cnt = (item_cnt / span); + if (item_cnt == 0 || item_cnt != span * seq_cnt) { + IRIS_LOGE("parse %s len is not right = %d", key, item_cnt); + return -EINVAL; + } + + *pval = pdata; + + return seq_cnt; +} + +static int32_t _iris_parse_cmd_seq_common( + struct device_node *np, const uint8_t *pre_key, + const uint8_t *key, struct iris_ctrl_seq *pctrl_seq) +{ + int32_t pre_seq_cnt = 0; + int32_t seq_cnt = 0; + int32_t sum = 0; + int32_t rc = 0; + const uint8_t *pdata = NULL; + const uint8_t *pre_pdata = NULL; + + pre_seq_cnt = _iris_parse_cmd_seq_data(np, pre_key, &pre_pdata); + if (pre_seq_cnt <= 0) + return -EINVAL; + + seq_cnt = _iris_parse_cmd_seq_data(np, key, &pdata); + if (seq_cnt <= 0) + return -EINVAL; + + sum = pre_seq_cnt + seq_cnt; + + rc = _iris_alloc_cmd_seq(pctrl_seq, sum); + if (rc != 0) + return rc; + + _iris_add_cmd_seq(pctrl_seq->ctrl_opt, pre_seq_cnt, pre_pdata); + _iris_add_cmd_seq(&pctrl_seq->ctrl_opt[pre_seq_cnt], seq_cnt, pdata); + + return rc; +} + +static int32_t _iris_parse_cmd_seq( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + uint8_t *pre0_key = "pxlw,iris-lightup-sequence-pre0"; + uint8_t *pre1_key = "pxlw,iris-lightup-sequence-pre1"; + uint8_t *key = "pxlw,iris-lightup-sequence"; + + rc = _iris_parse_cmd_seq_common(np, pre0_key, key, pcfg->ctrl_seq); + if (rc != 0) + return rc; + + return _iris_parse_cmd_seq_common(np, pre1_key, key, pcfg->ctrl_seq + 1); +} + +int32_t iris_parse_optional_seq(struct device_node *np, const uint8_t *key, + struct iris_ctrl_seq *pseq) +{ + int32_t rc = 0; + int32_t seq_cnt = 0; + const uint8_t *pdata = NULL; + + seq_cnt = _iris_parse_cmd_seq_data(np, key, &pdata); + if (seq_cnt <= 0) { + IRIS_LOGI("%s(), [optional] without sequence for %s, seq_cnt %d", + __func__, key, seq_cnt); + return 0; + } + + rc = _iris_alloc_cmd_seq(pseq, seq_cnt); + if (rc != 0) { + IRIS_LOGE("%s(), failed to alloc for %s seq, return %d", + __func__, key, rc); + return rc; + } + + _iris_add_cmd_seq(pseq->ctrl_opt, seq_cnt, pdata); + + return rc; +} + +/*use for debug cont-splash lk part*/ +static int32_t _iris_parse_cont_splash_cmd_seq( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + uint8_t *pre0_key = "pxlw,iris-lightup-sequence-pre0"; + uint8_t *pre1_key = "pxlw,iris-lightup-sequence-pre1"; + uint8_t *key = "pxlw,iris-lightup-sequence-cont-splash"; + + rc = _iris_parse_cmd_seq_common(np, pre0_key, key, pcfg->ctrl_seq_cs); + if (rc != 0) + return rc; + + return _iris_parse_cmd_seq_common(np, pre1_key, + key, pcfg->ctrl_seq_cs + 1); +} + +static int32_t _iris_parse_tx_mode( + struct device_node *np, + struct dsi_panel *panel, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + u8 tx_mode; + + pcfg->rx_mode = panel->panel_mode; + pcfg->tx_mode = panel->panel_mode; + IRIS_LOGE("%s, panel_mode = %d", __func__, panel->panel_mode); + rc = of_property_read_u8(np, "pxlw,iris-tx-mode", &tx_mode); + if (!rc) { + IRIS_LOGE("get property: pxlw, iris-tx-mode: %d", tx_mode); + //pcfg->tx_mode = tx_mode; + } + if (pcfg->rx_mode == pcfg->tx_mode) + pcfg->pwil_mode = PT_MODE; + else + pcfg->pwil_mode = RFB_MODE; + + IRIS_LOGI("%s(), pwil mode: %d", __func__, pcfg->pwil_mode); + return 0; +} + +static int _iris_parse_pwr_entries(struct dsi_display *display) +{ + int32_t rc = 0; + char *supply_name = NULL; + struct iris_cfg *pcfg = NULL; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!display || !display->panel) + return -EINVAL; + + if (!strcmp(display->panel->type, "primary")) { + supply_name = "qcom,iris-supply-entries"; + + rc = dsi_pwr_of_get_vreg_data(&display->panel->utils, + &pcfg->iris_power_info, supply_name); + if (rc) { + rc = -EINVAL; + IRIS_LOGE("%s pwr enters error", __func__); + } + } + return rc; +} + +static void __cont_splash_work_handler(struct work_struct *work) +{ + // struct iris_cfg *pcfg = iris_get_cfg(); + // bool done = false; + + // do { + // done = iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + // if (done) + // done = iris_abypass_switch_proc(pcfg->display, PASS_THROUGH_MODE, false, true); + // } while (!done); +} + +int iris_parse_param(struct dsi_display *display) +{ + int32_t rc = 0; + struct device_node *lightup_node = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->valid = PARAM_EMPTY; /* empty */ + + IRIS_LOGI("%s(%d), enter.", __func__, __LINE__); + if (!display || !display->pdev->dev.of_node || !display->panel_node) { + IRIS_LOGE("the param is null"); + return -EINVAL; + } + + if (display->panel->is_secondary) { + // Copy valid flag to 2nd iris cfg. + struct iris_cfg *pcfg1 = iris_get_cfg_by_index(DSI_PRIMARY); + + pcfg->valid = pcfg1->valid; + return 0; + } + + spin_lock_init(&pcfg->iris_1w_lock); + mutex_init(&pcfg->lb_mutex); + init_completion(&pcfg->frame_ready_completion); + + lightup_node = of_parse_phandle(display->pdev->dev.of_node, "pxlw,iris-lightup-config", 0); + if (!lightup_node) { + IRIS_LOGE("%s(), failed to find lightup node", __func__); + return -EINVAL; + } + IRIS_LOGI("%s(), lightup node: %s", __func__, lightup_node->name); + + rc = _iris_parse_split_pkt_info(lightup_node, pcfg); + if (rc) { + /*use 64 split packet and do not add last for every packet.*/ + pcfg->split_pkt_size = 64; + pcfg->add_last_flag = 0; + } + + iris_parse_color_temp_range(lightup_node, pcfg); + + rc = iris_parse_dtsi_cmd(lightup_node, IRIS_DTSI0_PIP_IDX); + if (rc) { + IRIS_LOGE("%s, parse cmds list failed", __func__); + return -EINVAL; + } + + rc = _iris_parse_cmd_seq(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse cmd seq error"); + return -EINVAL; + } + + rc = iris_parse_timing_switch_info(lightup_node, pcfg); + if (rc) + IRIS_LOGI("%s, [optional] have not timing switch info", __func__); + + rc = iris_parse_default_pq_param(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse pq init error"); + return -EINVAL; + } + + rc = _iris_parse_panel_type(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse panel type error"); + return -EINVAL; + } + + _iris_parse_lut_mode(lightup_node, pcfg); + + rc = _iris_parse_chip_ver(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse chip ver error"); + return -EINVAL; + } + + rc = iris_parse_lp_ctrl(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse low power control error"); + return -EINVAL; + } + + rc = _iris_parse_cont_splash_cmd_seq(lightup_node, pcfg); + if (rc) { + IRIS_LOGE("parse cont splash cmd seq error"); + return -EINVAL; + } + + rc = iris_parse_frc_setting(lightup_node, pcfg); + if (rc) + IRIS_LOGE("FRC not ready!"); + + rc = _iris_parse_tx_mode(lightup_node, display->panel, pcfg); + if (rc) + IRIS_LOGE("no set iris tx mode!"); + + rc = _iris_parse_pwr_entries(display); + if (rc) + IRIS_LOGE("pwr entries error\n"); + + iris_parse_loopback_info(lightup_node, pcfg); + + INIT_WORK(&pcfg->cont_splash_work, __cont_splash_work_handler); + + pcfg->valid = PARAM_PARSED; /* parse ok */ + IRIS_LOGI("%s(%d), exit.", __func__, __LINE__); + + return 0; +} + +struct iris_pq_ipopt_val *iris_get_cur_ipopt_val(uint8_t ip) +{ + int i = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_pq_init_val *pinit_val = &(pcfg->pq_init_val); + + for (i = 0; i < pinit_val->ip_cnt; i++) { + struct iris_pq_ipopt_val *pq_ipopt_val = pinit_val->val + i; + + if (ip == pq_ipopt_val->ip) + return pq_ipopt_val; + } + + return NULL; +} + +static void _iris_reset_out_cmds(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int sum = pcfg->dtsi_cmds_cnt + pcfg->lut_cmds_cnt; + + memset(pcfg->iris_cmds.iris_cmds_buf, 0x00, + sum * sizeof(struct dsi_cmd_desc)); + pcfg->iris_cmds.cmds_index = 0; +} + +static int32_t _iris_init_cmd_comp(int32_t ip, + int32_t opt_index, struct iris_cmd_comp *pcmd_comp) +{ + struct iris_ip_opt *opt = NULL; + + if (!_iris_is_valid_ip(ip)) { + IRIS_LOGE("%s(), invalid ip: %#x", __func__, ip); + return -EINVAL; + } + + opt = iris_find_ip_opt(ip, opt_index); + if (!opt) { + IRIS_LOGE("%s(), can not find popt, ip: %#x, opt: %#x", + __func__, ip, opt_index); + return -EINVAL; + } + + pcmd_comp->cmd = opt->cmd; + pcmd_comp->cnt = opt->cmd_cnt; + pcmd_comp->link_state = opt->link_state; + IRIS_LOGV("%s(), opt count: %d, link state: %#x", + __func__, pcmd_comp->cnt, pcmd_comp->link_state); + + return 0; +} + +void iris_print_desc_cmds(struct dsi_cmd_desc *p, int cmd_cnt, int state) +{ + int i = 0; + int j = 0; + int msg_len = 0; + int dlen = 0; + uint8_t *arr = NULL; + uint8_t *ptr = NULL; + uint8_t *ptr_tx = NULL; + struct dsi_cmd_desc *pcmd = NULL; + int str_len = 0;//CID99296 + + IRIS_LOGI("%s(), cmd len: %d, state: %s", __func__, cmd_cnt, + (state == DSI_CMD_SET_STATE_HS) ? "high speed" : "low power"); + + for (i = 0; i < cmd_cnt; i++) { + pcmd = p + i; + dlen = pcmd->msg.tx_len; + msg_len = 3 * dlen + 23; //3* 7(dchdr) + 1(\n) + 1 (0) + arr = vmalloc(msg_len * sizeof(uint8_t)); + if (!arr) { + IRIS_LOGE("%s(), fail to malloc space", __func__); + return; + } + memset(arr, 0x00, sizeof(uint8_t) * msg_len); + + ptr = arr; + ptr_tx = (uint8_t *) pcmd->msg.tx_buf; + str_len = snprintf(ptr, msg_len, "\" %02X", pcmd->msg.type); + ptr += str_len; + for (j = 0; j < dlen; j++) { + str_len = snprintf(ptr, msg_len - (ptr - arr), " %02X", ptr_tx[j]); + ptr += str_len; + } + snprintf(ptr, msg_len - (ptr - arr), "\\n\""); + IRIS_LOGE("%s", arr); + + if (pcmd->post_wait_ms > 0) + IRIS_LOGE("\" FF %02X\\n\"", pcmd->post_wait_ms); + + vfree(arr); + arr = NULL; + } +} + +static void _iris_print_spec_cmds(struct dsi_cmd_desc *p, int cmd_cnt) +{ + int i = 0; + int j = 0; + int value_count = 0; + int print_count = 0; + struct dsi_cmd_desc *pcmd = NULL; + uint32_t *pval = NULL; + + if (IRIS_IF_NOT_LOGD()) + return; + + IRIS_LOGD("%s(), package count in cmd list: %d", __func__, cmd_cnt); + for (i = 0; i < cmd_cnt; i++) { + pcmd = p + i; + value_count = pcmd->msg.tx_len/sizeof(uint32_t); + print_count = value_count; + if (value_count > 16) + print_count = 16; + pval = (uint32_t *)pcmd->msg.tx_buf; + if (i == 0 || i == cmd_cnt-1) { + IRIS_LOGD("%s(), package: %d, type: 0x%02x, last: %s, channel: 0x%02x, flags: 0x%04x, wait: 0x%02x, send size: %zu.", + __func__, i, + pcmd->msg.type, pcmd->last_command?"true":"false", pcmd->msg.channel, + pcmd->msg.flags, pcmd->post_wait_ms, pcmd->msg.tx_len); + + if (IRIS_IF_NOT_LOGV()) + continue; + + IRIS_LOGV("%s(), payload value count: %d, print count: %d, ocp type: 0x%08x, addr: 0x%08x", + __func__, value_count, print_count, pval[0], pval[1]); + for (j = 2; j < print_count; j++) + IRIS_LOGV("0x%08x", pval[j]); + + if (i == cmd_cnt-1 && value_count > 4 && print_count != value_count) { + IRIS_LOGV("%s(), payload tail: 0x%08x, 0x%08x, 0x%08x, 0x%08x.", __func__, + pval[value_count-4], pval[value_count-3], + pval[value_count-2], pval[value_count-1]); + } + } + } +} + +static void _iris_print_dtsi_cmds_for_lk(struct dsi_cmd_desc *cmds, + int32_t cnt, int32_t wait, int32_t link_state) +{ + if (iris_get_cont_splash_type() != IRIS_CONT_SPLASH_LK) + return; + + //restore the last cmd wait time + if (wait != 0) + cmds[cnt-1].post_wait_ms = 1; + + iris_print_desc_cmds(cmds, cnt, link_state); +} + +static int32_t _iris_i2c_send_ocp_cmds(struct dsi_panel *panel, + struct iris_cmd_comp *pcmd_comp) +{ + int i = 0; + int ret = 0; + bool is_burst; + bool is_allburst = true; + int len = 0; + uint32_t *payload = NULL; + uint32_t header = 0; + struct iris_i2c_msg *msg = NULL; + uint32_t iris_i2c_msg_num = 0; + + for (i = 0; i < pcmd_comp->cnt; i++) { + is_burst = _iris_is_direct_bus(pcmd_comp->cmd[i].msg.tx_buf); + if (is_burst == false) { + is_allburst = false; + break; + } + } + + if (!is_allburst) { + for (i = 0; i < pcmd_comp->cnt; i++) { + header = *(uint32_t *)(pcmd_comp->cmd[i].msg.tx_buf); + payload = (uint32_t *)(pcmd_comp->cmd[i].msg.tx_buf) + 1; + len = (pcmd_comp->cmd[i].msg.tx_len >> 2) - 1; + is_burst = _iris_is_direct_bus(pcmd_comp->cmd[i].msg.tx_buf); + if (is_burst) { + if ((header & 0x0f) == 0x0c) + iris_i2c_direct_write(payload, len-1, header); + else + iris_i2c_ocp_burst_write(payload, len-1); + } else { + iris_i2c_ocp_single_write(payload, len/2); + } + } + + return 0; + } + + iris_i2c_msg_num = pcmd_comp->cnt; + msg = vmalloc(sizeof(struct iris_i2c_msg) * iris_i2c_msg_num + 1); + if (msg == NULL) { + IRIS_LOGE("[iris] %s: allocate memory fails", __func__); + return -EINVAL; + } + for (i = 0; i < iris_i2c_msg_num; i++) { + msg[i].payload = (uint32_t *)(pcmd_comp->cmd[i].msg.tx_buf) + 1; + msg[i].len = (pcmd_comp->cmd[i].msg.tx_len >> 2) - 1; + msg[i].base_addr = *(uint32_t *)(pcmd_comp->cmd[i].msg.tx_buf); + } + ret = iris_i2c_burst_write(msg, iris_i2c_msg_num); + vfree(msg); + + return ret; +} + + +static int32_t _iris_dsi_send_ocp_cmds(struct dsi_panel *panel, struct iris_cmd_comp *pcmd_comp) +{ + int ret; + uint32_t wait = 0; + struct dsi_cmd_desc *cmd = NULL; + + if (!pcmd_comp) { + IRIS_LOGE("%s(), cmd list is null.", __func__); + return -EINVAL; + } + + /*use us than ms*/ + cmd = pcmd_comp->cmd + pcmd_comp->cnt - 1; + wait = cmd->post_wait_ms; + if (wait) + cmd->post_wait_ms = 0; + + ret = iris_dsi_send_cmds(panel, pcmd_comp->cmd, + pcmd_comp->cnt, pcmd_comp->link_state); + if (wait) + udelay(wait); + + _iris_print_spec_cmds(pcmd_comp->cmd, pcmd_comp->cnt); + _iris_print_dtsi_cmds_for_lk(pcmd_comp->cmd, pcmd_comp->cnt, wait, pcmd_comp->link_state); + + return ret; +} + +int32_t _iris_send_cmds(struct dsi_panel *panel, + struct iris_cmd_comp *pcmd_comp, uint8_t path) +{ + int32_t ret = 0; + + IRIS_LOGD("%s,%d: path = %d", __func__, __LINE__, path); + + if (!pcmd_comp) { + IRIS_LOGE("cmd list is null"); + return -EINVAL; + } + + if (path == PATH_DSI) + ret = _iris_dsi_send_ocp_cmds(panel, pcmd_comp); + else if (path == PATH_I2C) + ret = _iris_i2c_send_ocp_cmds(panel, pcmd_comp); + else + ret = -EINVAL; + + return ret; +} + +static void _iris_send_panel_cmd(struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmds) +{ + if (!cmds || !cmds->count) { + IRIS_LOGE("cmds = %p or cmd_cnt = 0", cmds); + return; + } + + iris_pt_send_panel_cmd(panel, cmds); +} + +int32_t iris_send_ipopt_cmds(int32_t ip, int32_t opt_id) +{ + int32_t rc = 0; + struct iris_cmd_comp cmd_comp; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + IRIS_LOGD("%s(), ip: %#x, opt: %#x.", __func__, ip, opt_id); + rc = _iris_init_cmd_comp(ip, opt_id, &cmd_comp); + if (rc) { + IRIS_LOGE("%s(), can not find in seq for ip: 0x%02x opt: 0x%02x.", + __func__, ip, opt_id); + return rc; + } + + return _iris_send_cmds(pcfg->panel, &cmd_comp, PATH_DSI); +} + +/********************************************** + * the API will only be called when suspend/resume and boot up. + * + ***********************************************/ +static void _iris_send_spec_lut(uint8_t lut_table, uint8_t lut_idx) +{ + if (lut_table == AMBINET_HDR_GAIN + || lut_table == AMBINET_SDR2HDR_LUT) + return; + + if (lut_table == DBC_LUT && lut_idx < CABC_DLV_OFF) + iris_send_lut(lut_table, lut_idx, 1); + + iris_send_lut(lut_table, lut_idx, 0); +} + +static void _iris_send_new_lut(uint8_t lut_table, uint8_t lut_idx) +{ + uint8_t dbc_lut_index = 0; + + if (lut_table == DBC_LUT) + dbc_lut_index = iris_get_dbc_lut_index(); + + iris_send_lut(lut_table, lut_idx, dbc_lut_index); +} + +static void _iris_update_cmds(struct iris_cmd_comp *pcmd_comp, int32_t link_state) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + _iris_reset_out_cmds(); + + memset(pcmd_comp, 0x00, sizeof(*pcmd_comp)); + pcmd_comp->cmd = pcfg->iris_cmds.iris_cmds_buf; + pcmd_comp->link_state = link_state; + pcmd_comp->cnt = pcfg->iris_cmds.cmds_index; +} + +static void _iris_update_desc_last(struct dsi_cmd_desc *pcmd, + int count, bool last_cmd) +{ + int i = 0; + + for (i = 0; i < count; i++) + pcmd[i].last_command = last_cmd; +} + +static void _iris_add_last_pkt(struct dsi_cmd_desc *cmd, int cmd_cnt) +{ + _iris_update_desc_last(cmd, cmd_cnt, false); + _iris_update_desc_last(cmd + cmd_cnt - 1, 1, true); +} + +static void _iris_update_mult_pkt_last(struct dsi_cmd_desc *cmd, + int cmd_cnt, int skip_last) +{ + int i = 0; + int pos = 0; + int num = 0; + int surplus = 0; + int span = 0; + static int sum; + struct iris_cfg *pcfg = iris_get_cfg(); + int prev = sum; + + sum += cmd_cnt; + + span = pcfg->add_last_flag; + + num = sum / span; + surplus = sum - num * span; + + for (i = 0; i < num; i++) { + if (i == 0) { + _iris_add_last_pkt(cmd, span - prev); + } else { + pos = i * span - prev; + _iris_add_last_pkt(cmd + pos, span); + } + } + pos = cmd_cnt - surplus; + + if (skip_last) { + _iris_update_desc_last(cmd + pos, surplus, false); + sum = surplus; + } else { + _iris_add_last_pkt(cmd + pos, surplus); + sum = 0; + } +} + +static int _iris_set_pkt_last(struct dsi_cmd_desc *cmd, + int cmd_cnt, int skip_last) +{ + int32_t ret = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + int32_t add_last_flag = pcfg->add_last_flag; + + switch (add_last_flag) { + case DSI_CMD_ONE_LAST_FOR_MULT_IPOPT: + _iris_update_desc_last(cmd, cmd_cnt, false); + _iris_update_desc_last(cmd + cmd_cnt - 1, 1, true); + break; + case DSI_CMD_ONE_LAST_FOR_ONE_IPOPT: + /*only add the last packet*/ + _iris_update_desc_last(cmd, cmd_cnt - 1, false); + _iris_update_desc_last(cmd + cmd_cnt - 1, 1, true); + + break; + case DSI_CMD_ONE_LAST_FOR_ONE_PKT: + /*add all packets*/ + _iris_update_desc_last(cmd, cmd_cnt, true); + break; + default: + _iris_update_mult_pkt_last(cmd, cmd_cnt, skip_last); + break; + } + + return ret; +} + +static int _iris_send_lut_pkt( + struct iris_ctrl_opt *popt, struct iris_cmd_comp *pcomp, + bool is_update, uint8_t path) +{ + int32_t cur = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + uint8_t ip = popt->ip; + uint8_t opt_id = popt->opt_id; + int32_t skip_last = popt->skip_last; + int32_t prev = pcomp->cnt; + + IRIS_LOGD("%s(), ip: %#x opt: %#x, skip last: %d, update: %s", + __func__, ip, opt_id, skip_last, is_update ? "true" : "false"); + + pcfg->iris_cmds.cmds_index = prev; + if (is_update) + _iris_send_new_lut(ip, opt_id); + else + _iris_send_spec_lut(ip, opt_id); + + cur = pcfg->iris_cmds.cmds_index; + if (cur == prev) { + IRIS_LOGD("lut table is empty for ip: %02x opt: %02x", + popt->ip, opt_id); + return 0; + } + + pcomp->cnt = cur; + + _iris_set_pkt_last(pcomp->cmd + prev, cur - prev, skip_last); + if (!skip_last) { + _iris_send_cmds(pcfg->panel, pcomp, path); + _iris_update_cmds(pcomp, pcomp->link_state); + } + + return 0; +} + +static int _iris_send_dtsi_pkt( + struct iris_ctrl_opt *pip_opt, struct iris_cmd_comp *pcomp, uint8_t path) +{ + uint8_t ip = 0; + uint8_t opt_id = 0; + int32_t flag = 0; + int32_t prev = 0; + int32_t cur = 0; + int32_t skip_last = 0; + int32_t add_last_flag = 0; + int32_t rc = 0; + struct iris_cfg *pcfg = NULL; + struct iris_cmd_comp comp_priv; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + ip = pip_opt->ip; + opt_id = pip_opt->opt_id; + skip_last = pip_opt->skip_last; + add_last_flag = pcfg->add_last_flag; + + IRIS_LOGD("%s(), ip: %#x opt: %#x, skip last: %d.", + __func__, ip, opt_id, skip_last); + + /*get single/multiple selection(s) according to option of ip*/ + rc = _iris_init_cmd_comp(ip, opt_id, &comp_priv); + if (rc) { + IRIS_LOGE("%s(), invalid ip: %#x opt: %#x.", __func__, ip, opt_id); + return -EINVAL; + } + + if (pcomp->cnt == 0) + pcomp->link_state = comp_priv.link_state; + else if (comp_priv.link_state != pcomp->link_state) + flag = 1; /*send link state different packet.*/ + + if (flag == 0) { + prev = pcomp->cnt; + /*move single/multiples selection to one command*/ + + memcpy(pcomp->cmd + pcomp->cnt, comp_priv.cmd, + comp_priv.cnt * sizeof(*comp_priv.cmd)); + pcomp->cnt += comp_priv.cnt; + + cur = pcomp->cnt; + _iris_set_pkt_last(pcomp->cmd + prev, cur - prev, skip_last); + } + + /* if need to send or the last packet of sequence, + * it should send out to the MIPI + */ + if (!skip_last || flag == 1) { + _iris_send_cmds(pcfg->panel, pcomp, path); + _iris_update_cmds(pcomp, pcomp->link_state); + } + + return 0; +} + +void iris_send_pkt(struct iris_ctrl_opt *arr, int seq_cnt, + struct iris_cmd_comp *pcmd_comp) +{ + int i = 0; + uint8_t ip = 0; + uint8_t opt_id = 0; + int32_t rc = -1; + + for (i = 0; i < seq_cnt; i++) { + ip = arr[i].ip; + opt_id = arr[i].opt_id; + IRIS_LOGV("%s(), ip:%0x opt:%0x", __func__, ip, opt_id); + + /*lut table*/ + if (_iris_is_lut(ip)) + rc = _iris_send_lut_pkt(arr + i, pcmd_comp, false, PATH_DSI); + else + rc = _iris_send_dtsi_pkt(arr + i, pcmd_comp, PATH_DSI); + + if (rc) + IRIS_LOGE("%s(), [FATAL ERROR] invalid ip: %0x opt: %0x", __func__, ip, opt_id); + } +} + +void iris_send_assembled_pkt(struct iris_ctrl_opt *arr, int seq_cnt) +{ + struct iris_cmd_comp cmd_comp; + + _iris_update_cmds(&cmd_comp, DSI_CMD_SET_STATE_HS); + iris_send_pkt(arr, seq_cnt, &cmd_comp); +} + +static void _iris_send_lightup_pkt(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_ctrl_seq *pseq = _iris_get_ctrl_seq(pcfg); + + iris_send_assembled_pkt(pseq->ctrl_opt, pseq->cnt); +} + +void iris_init_update_ipopt( + struct iris_update_ipopt *popt, uint8_t ip, + uint8_t opt_old, uint8_t opt_new, uint8_t skip_last) +{ + popt->ip = ip; + popt->opt_old = opt_old; + popt->opt_new = opt_new; + popt->skip_last = skip_last; +} + +int iris_init_update_ipopt_t(struct iris_update_ipopt *popt, int max_cnt, + uint8_t ip, uint8_t opt_old, uint8_t opt_new, uint8_t skip_last) +{ + int i = 0; + int cnt = 0; + + for (i = 0; i < max_cnt; i++) { + if (popt[i].ip == 0xff) + break; + } + + if (i >= max_cnt) { + IRIS_LOGE("%s(), no empty space to install ip: %#x, opt old: %#x, opt new: %#x", + __func__, ip, opt_old, opt_new); + return -EINVAL; + } + + iris_init_update_ipopt(&popt[i], ip, opt_old, opt_new, skip_last); + cnt = i + 1; + + return cnt; +} + +static int _iris_read_chip_id(void) +{ + // uint32_t sys_pll_ro_status = 0xf0000010; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->chip_value[0] != 0) + pcfg->chip_value[1] = iris_ocp_read(pcfg->chip_value[0], DSI_CMD_SET_STATE_HS); + + // FIXME: if chip version is set by sw, skip hw read chip id. + // if (pcfg->chip_ver == IRIS3_CHIP_VERSION) + // pcfg->chip_id = (iris_ocp_read(sys_pll_ro_status, DSI_CMD_SET_STATE_HS)) & 0xFF; + // else + pcfg->chip_id = 0; + + IRIS_LOGI("%s(), chip version: %#x, chip id: %#x", + __func__, pcfg->chip_ver, pcfg->chip_id); + + return pcfg->chip_id; +} + +static void _iris_clean_status(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + iris_clean_frc_status(pcfg); +} + +void iris_free_ipopt_buf(uint32_t ip_type) +{ + int ip_index = 0; + int opt_index = 0; + uint32_t desc_index = 0; + int ip_cnt = IRIS_IP_CNT; + struct dsi_cmd_desc *pdesc_addr = NULL; + struct iris_ip_index *pip_index = iris_get_ip_idx(ip_type); + + if (ip_type == IRIS_LUT_PIP_IDX) + ip_cnt = LUT_IP_END - LUT_IP_START; + + for (ip_index = 0; ip_index < ip_cnt; ip_index++) { + if (pip_index[ip_index].opt_cnt == 0 || pip_index[ip_index].opt == NULL) + continue; + + for (opt_index = 0; opt_index < pip_index[ip_index].opt_cnt; opt_index++) { + if (pip_index[ip_index].opt[opt_index].cmd_cnt == 0 + || pip_index[ip_index].opt[opt_index].cmd == NULL) + continue; + + /* get desc cmd start address */ + if (pdesc_addr == NULL || pip_index[ip_index].opt[opt_index].cmd < pdesc_addr) + pdesc_addr = pip_index[ip_index].opt[opt_index].cmd; + + for (desc_index = 0; desc_index < pip_index[ip_index].opt[opt_index].cmd_cnt; desc_index++) { + if (pip_index[ip_index].opt[opt_index].cmd[desc_index].msg.tx_buf == NULL + || pip_index[ip_index].opt[opt_index].cmd[desc_index].msg.tx_len == 0) + continue; + + /* free cmd payload, which alloc in "_iris_write_cmd_payload()" */ + vfree(pip_index[ip_index].opt[opt_index].cmd[desc_index].msg.tx_buf); + pip_index[ip_index].opt[opt_index].cmd[desc_index].msg.tx_buf = NULL; + } + + /* set each desc cmd to NULL first */ + pip_index[ip_index].opt[opt_index].cmd = NULL; + } + + /* free opt buffer for each ip, which alloc in "_iris_alloc_pip_buf()" */ + kvfree(pip_index[ip_index].opt); + pip_index[ip_index].opt = NULL; + pip_index[ip_index].opt_cnt = 0; + } + + /* free desc cmd buffer, which alloc in "_iris_alloc_desc_buf()", desc + * cmd buffer is continus memory, so only free once on start address + */ + if (pdesc_addr != NULL) { + IRIS_LOGI("%s(), free desc cmd buffer %p, type %#x", __func__, pdesc_addr, ip_type); + vfree(pdesc_addr); + pdesc_addr = NULL; + } +} + +void iris_free_seq_space(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + /* free cmd to sent buffer, which alloc in "iris_alloc_seq_space()" */ + if (pcfg->iris_cmds.iris_cmds_buf != NULL) { + IRIS_LOGI("%s(), free %p", __func__, pcfg->iris_cmds.iris_cmds_buf); + vfree(pcfg->iris_cmds.iris_cmds_buf); + pcfg->iris_cmds.iris_cmds_buf = NULL; + } + +} + +void iris_alloc_seq_space(void) +{ + struct dsi_cmd_desc *pdesc = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + int sum = pcfg->dtsi_cmds_cnt + pcfg->lut_cmds_cnt; + + IRIS_LOGI("%s(), seq = %u, lut = %u", __func__, + pcfg->dtsi_cmds_cnt, pcfg->lut_cmds_cnt); + + sum *= sizeof(struct dsi_cmd_desc); + pdesc = vmalloc(sum); + if (!pdesc) { + IRIS_LOGE("%s(), failed to alloc buffer", __func__); + return; + } + pcfg->iris_cmds.iris_cmds_buf = pdesc; + + IRIS_LOGI("%s(), alloc %p", __func__, pcfg->iris_cmds.iris_cmds_buf); + _iris_reset_out_cmds(); + + // Need to init PQ parameters here for video panel. + iris_pq_parameter_init(); +} + +static void _iris_load_mcu(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 values[2] = {0xF00000C8, 0x1}; + struct iris_ctrl_opt ctrl_opt; + + IRIS_LOGI("%s(%d): load and run mcu", __func__, __LINE__); + ctrl_opt.ip = APP_CODE_LUT; + ctrl_opt.opt_id = 0; + ctrl_opt.skip_last = 0; + + iris_send_assembled_pkt(&ctrl_opt, 1); + iris_ocp_write_mult_vals(2, values); + pcfg->mcu_code_downloaded = true; +} + +static void _iris_pre_lightup(struct dsi_panel *panel) +{ + static int num; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_update_ipopt popt[IP_OPT_MAX]; + int len = 0; + bool high = false; + + if ((panel->cur_mode->timing.refresh_rate == HIGH_FREQ) + && (pcfg->panel->cur_mode->timing.v_active == FHD_H)) + high = true; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + //sys pll + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SYS, high ? 0xA1:0xA0, 0x1); + //dtg + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DTG, high ? 0x1:0x0, 0x1); + //mipi tx + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_TX, high ? 0x4:0x0, 0x1); + //mipi abp + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_RX, high ? 0xE1:0xE0, 0x0); + _iris_update_pq_seq(popt, len); + + /*send rx cmds first with low power*/ + iris_send_ipopt_cmds(IRIS_IP_RX, high ? 0xF2 : 0xF1); + + //if (num == 0) { + if (1) { + /*read chip_id*/ + _iris_read_chip_id(); + num++; + } + + iris_pq_parameter_init(); + iris_frc_parameter_init(); + _iris_clean_status(); +} + +void _iris_read_power_mode(struct dsi_panel *panel) +{ + char get_power_mode[1] = {0x0a}; + char read_cmd_rbuf[16] = {0}; + struct dsi_cmd_desc cmds = { + {0, MIPI_DSI_DCS_READ, MIPI_DSI_MSG_REQ_ACK, 0, 0, sizeof(get_power_mode), get_power_mode, 1, read_cmd_rbuf}, 1, 0}; + struct dsi_panel_cmd_set cmdset = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &cmds, + }; + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGI("%s(%d), abyp mode: %d", __func__, __LINE__, + pcfg->abypss_ctrl.abypass_mode); + if (pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) { + iris_dsi_send_cmds(panel, cmdset.cmds, cmdset.count, cmdset.state); + } else { + iris_dsi_send_cmds(panel, cmdset.cmds, cmdset.count, cmdset.state); + IRIS_LOGE("[a]power mode: 0x%02x", read_cmd_rbuf[0]); + read_cmd_rbuf[0] = 0; + _iris_send_panel_cmd(panel, &cmdset); + } + pcfg->power_mode = read_cmd_rbuf[0]; + + IRIS_LOGI("%s(), power mode: 0x%02x", __func__, pcfg->power_mode); +} + +int iris_lightup(struct dsi_panel *panel, + struct dsi_panel_cmd_set *on_cmds) +{ + ktime_t ktime0; + ktime_t ktime1; + uint32_t timeus0 = 0; + uint32_t timeus1 = 0; + uint8_t type = 0; + struct dsi_display *display = to_dsi_display(panel->host); + int rc; + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGI("%s(%d), mode: %s(%d) +++", __func__, __LINE__, + pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE ? "PT" : "ABYP", + pcfg->abypss_ctrl.abypass_mode); + + ktime0 = ktime_get(); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + IRIS_LOGE("%s(), failed to enable all DSI clocks for display: %s, return: %d", + __func__, display->name, rc); + } + + rc = iris_display_cmd_engine_enable(display); + if (rc) { + IRIS_LOGE("%s(), failed to enable cmd engine for display: %s, return: %d", + __func__, display->name, rc); + } + + pcfg->add_last_flag = pcfg->add_on_last_flag; + + iris_set_pinctrl_state(pcfg, true); + _iris_pre_lightup(panel); + + type = iris_get_cont_splash_type(); + + /*use to debug cont splash*/ + if (type == IRIS_CONT_SPLASH_LK) { + IRIS_LOGI("%s(%d), enter cont splash", __func__, __LINE__); + _iris_send_cont_splash_pkt(IRIS_CONT_SPLASH_LK); + } else { + _iris_send_lightup_pkt(); + iris_scaler_filter_ratio_get(); + iris_update_gamma(); + if (!(pcfg->dual_test & 0x20)) + iris_dual_setting_switch(pcfg->dual_setting); + } + + _iris_load_mcu(); + + if (panel->bl_config.type == DSI_BACKLIGHT_PWM) + iris_pwm_freq_set(panel->bl_config.pwm_period_usecs); + + ktime1 = ktime_get(); + if (on_cmds) + _iris_send_panel_cmd(panel, on_cmds); + + if (type == IRIS_CONT_SPLASH_LK) + IRIS_LOGI("%s(), exit cont splash", __func__); + else + /*continuous splahs should not use dma setting low power*/ + iris_lp_init(); + + pcfg->add_last_flag = pcfg->add_pt_last_flag; + + rc = iris_display_cmd_engine_disable(display); + if (rc) { + IRIS_LOGE("%s(), failed to disable cmd engine for display: %s, return: %d", + __func__, display->name, rc); + } + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + IRIS_LOGE("%s(), failed to disable all DSI clocks for display: %s, return: %d", + __func__, display->name, rc); + } + + pcfg->cur_fps_in_iris = panel->cur_mode->timing.refresh_rate; + pcfg->cur_vres_in_iris = panel->cur_mode->timing.v_active; + iris_update_frc_fps(pcfg->cur_fps_in_iris & 0xFF); + + timeus0 = (u32) ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + timeus1 = (u32) ktime_to_us(ktime_get()) - (u32)ktime_to_us(ktime1); + IRIS_LOGI("%s() spend time0 %d us, time1 %d us.", + __func__, timeus0, timeus1); + +#ifdef IRIS_MIPI_TEST + _iris_read_power_mode(panel); +#endif + IRIS_LOGI("%s(), end +++", __func__); + + return 0; +} + +int iris_enable(struct dsi_panel *panel, struct dsi_panel_cmd_set *on_cmds) +{ + int rc = 0; + struct iris_cfg *pcfg = NULL; +#ifndef IRIS_HDK_DEV // skip preload + int abyp_status_gpio; + int prev_mode; +#endif + int lightup_opt = iris_lightup_opt_get(); + + pcfg = iris_get_cfg_by_index(panel->is_secondary ? DSI_SECONDARY : DSI_PRIMARY); + + if (panel->is_secondary) { + if (pcfg->iris_osd_autorefresh) { + IRIS_LOGI("reset iris_osd_autorefresh"); + iris_osd_autorefresh(0); + } + return rc; + } + + iris_lp_preinit(); + + pcfg->iris_initialized = false; + +#ifndef IRIS_HDK_DEV // skip preload + pcfg->next_fps_for_iris = panel->cur_mode->timing.refresh_rate; + + /* Special process for WQHD@120Hz */ + if (panel->cur_mode->timing.refresh_rate == HIGH_FREQ + && panel->cur_mode->timing.v_active == QHD_H) { + /* Force Iris work in ABYP mode */ + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + } +#endif + + IRIS_LOGI("%s(), mode:%d, rate: %d, v: %d, on_opt:0x%x", + __func__, + pcfg->abypss_ctrl.abypass_mode, + panel->cur_mode->timing.refresh_rate, + panel->cur_mode->timing.v_active, + lightup_opt); + + // if (pcfg->fod == true && pcfg->fod_pending) { + // iris_abyp_lp(1); + // pcfg->abyp_prev_mode = pcfg->abypss_ctrl.abypass_mode; + // pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + // pcfg->fod_pending = false; + // pcfg->initialized = false; + // IRIS_LOGD("[%s:%d] fod = 1 in init, ABYP prev mode: %d ABYP mode: %d", + // __func__, __LINE__, pcfg->abyp_prev_mode, pcfg->abypss_ctrl.abypass_mode); + // return rc; + // } + + /* support lightup_opt */ + if (lightup_opt & 0x1) { + if (on_cmds != NULL) + rc = iris_dsi_send_cmds(panel, on_cmds->cmds, on_cmds->count, on_cmds->state); + IRIS_LOGI("%s(), force ABYP lightup.", __func__); + return rc; + } + +#ifndef IRIS_HDK_DEV // skip preload + prev_mode = pcfg->abypss_ctrl.abypass_mode; + + abyp_status_gpio = iris_exit_abyp(false); + if (abyp_status_gpio == 1) { + IRIS_LOGE("%s(), failed to exit abyp!", __func__); + return rc; + } +#endif + + if (pcfg->loop_back_mode == 1) { + pcfg->loop_back_mode_res = iris_loop_back_verify(); + return rc; + } + +#ifndef IRIS_HDK_DEV // skip preload + rc = iris_lightup(panel, NULL); + pcfg->iris_initialized = true; + if (on_cmds != NULL) + rc = iris_pt_send_panel_cmd(panel, on_cmds); + if (pcfg->lp_ctrl.esd_cnt > 0) /* restore brightness setting for esd */ + iris_panel_nits_set(0, true, 0); + //iris_set_out_frame_rate(panel->cur_mode->timing.refresh_rate); + pcfg->abypss_ctrl.abypass_mode = PASS_THROUGH_MODE; +#else + if (on_cmds != NULL) + rc = iris_dsi_send_cmds(panel, on_cmds->cmds, on_cmds->count, on_cmds->state); +#endif + +#ifndef IRIS_HDK_DEV // skip preload + //Switch back to ABYP mode if need + if (prev_mode == ANALOG_BYPASS_MODE) + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); +#endif + + return rc; +} + +int iris_set_aod(struct dsi_panel *panel, bool aod) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!pcfg) + return rc; + + if (panel->is_secondary) + return rc; + + IRIS_LOGI("%s(%d), aod: %d", __func__, __LINE__, aod); + if (pcfg->aod == aod) { + IRIS_LOGI("[%s:%d] aod: %d no change", __func__, __LINE__, aod); + return rc; + } + + if (aod) { + if (!pcfg->fod) { + pcfg->abyp_prev_mode = pcfg->abypss_ctrl.abypass_mode; + if (iris_get_abyp_mode(panel) == PASS_THROUGH_MODE) + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + } + } else { + if (!pcfg->fod) { + if (iris_get_abyp_mode(panel) == ANALOG_BYPASS_MODE && + pcfg->abyp_prev_mode == PASS_THROUGH_MODE && + !pcfg->fod) { + iris_abypass_switch_proc(pcfg->display, PASS_THROUGH_MODE, false, true); + } + } + } + + if (pcfg->fod_pending) + pcfg->fod_pending = false; + pcfg->aod = aod; + + return rc; +} + +int iris_set_fod(struct dsi_panel *panel, bool fod) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!pcfg) + return rc; + + if (panel->is_secondary) + return rc; + + IRIS_LOGD("%s(%d), fod: %d", __func__, __LINE__, fod); + if (pcfg->fod == fod) { + IRIS_LOGD("%s(%d), fod: %d no change", __func__, __LINE__, fod); + return rc; + } + + if (!dsi_panel_initialized(panel)) { + IRIS_LOGD("%s(%d), panel is not initialized fod: %d", __func__, __LINE__, fod); + pcfg->fod_pending = true; + atomic_set(&pcfg->fod_cnt, 1); + pcfg->fod = fod; + return rc; + } + + if (fod) { + if (!pcfg->aod) { + pcfg->abyp_prev_mode = pcfg->abypss_ctrl.abypass_mode; + if (iris_get_abyp_mode(panel) == PASS_THROUGH_MODE) + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + } + } else { + /* pending until hbm off cmds sent in update_hbm 1->0 */ + pcfg->fod_pending = true; + atomic_set(&pcfg->fod_cnt, 1); + } + + pcfg->fod = fod; + + return rc; +} + +int iris_post_fod(struct dsi_panel *panel) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!pcfg) + return rc; + + if (panel->is_secondary) + return rc; + + if (atomic_read(&pcfg->fod_cnt) > 0) { + IRIS_LOGD("%s(%d), fod delay %d", __func__, __LINE__, atomic_read(&pcfg->fod_cnt)); + atomic_dec(&pcfg->fod_cnt); + return rc; + } + + IRIS_LOGD("%s(%d), fod: %d", __func__, __LINE__, pcfg->fod); + + if (pcfg->fod) { + if (!pcfg->aod) { + pcfg->abyp_prev_mode = pcfg->abypss_ctrl.abypass_mode; + if (iris_get_abyp_mode(panel) == PASS_THROUGH_MODE) + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + } + } else { + if (!pcfg->aod) { + if (iris_get_abyp_mode(panel) == ANALOG_BYPASS_MODE && + pcfg->abyp_prev_mode == PASS_THROUGH_MODE) { + iris_abypass_switch_proc(pcfg->display, PASS_THROUGH_MODE, false, true); + } + } + } + + pcfg->fod_pending = false; + + return rc; +} + +bool iris_get_aod(struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (!panel || !pcfg) + return false; + + return pcfg->aod; +} + +static void _iris_clear_aod_state(void) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg->aod) { + pcfg->aod = false; + pcfg->abypss_ctrl.abypass_mode = pcfg->abyp_prev_mode; + } +} + +/*check whether it is in initial cont-splash packet*/ +static bool _iris_check_cont_splash_ipopt(uint8_t ip, uint8_t opt_id) +{ + int i = 0; + uint8_t cs_ip = 0; + uint8_t cs_opt_id = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_ctrl_seq *pseq_cs = _iris_get_ctrl_seq_cs(pcfg); + + for (i = 0; i < pseq_cs->cnt; i++) { + cs_ip = pseq_cs->ctrl_opt[i].ip; + cs_opt_id = pseq_cs->ctrl_opt[i].opt_id; + + if (ip == cs_ip && opt_id == cs_opt_id) + return true; + } + + return false; +} + +/*select ip/opt to the opt_arr according to lightup stage type*/ +static int _iris_select_cont_splash_ipopt( + int type, struct iris_ctrl_opt *opt_arr) +{ + uint32_t i = 0; + uint32_t j = 0; + uint8_t ip = 0; + uint8_t opt_id = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_ctrl_seq *pseq = _iris_get_ctrl_seq(pcfg); + struct iris_ctrl_opt *pctrl_opt = NULL; + + for (i = 0; i < pseq->cnt; i++) { + pctrl_opt = pseq->ctrl_opt + i; + ip = pctrl_opt->ip; + opt_id = pctrl_opt->opt_id; + + if (_iris_check_cont_splash_ipopt(ip, opt_id)) + continue; + + memcpy(opt_arr + j, pctrl_opt, sizeof(*pctrl_opt)); + j++; + } + + IRIS_LOGD("%s(), real len: %d", __func__, j); + return j; +} + +static void _iris_send_cont_splash_pkt(uint32_t type) +{ + int seq_cnt = 0; + uint32_t size = 0; + const int iris_max_opt_cnt = 30; + struct iris_ctrl_opt *opt_arr = NULL; + struct iris_cfg *pcfg = NULL; + struct iris_ctrl_seq *pseq_cs = NULL; + bool pt_mode; + + size = IRIS_IP_CNT * iris_max_opt_cnt * sizeof(struct iris_ctrl_opt); + opt_arr = vmalloc(size); + if (opt_arr == NULL) { + IRIS_LOGE("%s(), failed to malloc buffer!", __func__); + return; + } + + pcfg = iris_get_cfg(); + memset(opt_arr, 0xff, size); + + if (type == IRIS_CONT_SPLASH_LK) { + pseq_cs = _iris_get_ctrl_seq_cs(pcfg); + iris_send_assembled_pkt(pseq_cs->ctrl_opt, pseq_cs->cnt); + pcfg->iris_initialized = true; + } else if (type == IRIS_CONT_SPLASH_KERNEL) { + seq_cnt = _iris_select_cont_splash_ipopt(type, opt_arr); + /*stop video -->set pq --> start video*/ + iris_sde_encoder_rc_lock(); + msleep(20); + iris_send_assembled_pkt(opt_arr, seq_cnt); + iris_sde_encoder_rc_unlock(); + iris_lp_init(); + _iris_read_chip_id(); + pcfg->iris_initialized = true; + } else if (type == IRIS_CONT_SPLASH_BYPASS) { + iris_lp_preinit(); + pcfg->iris_initialized = false; + pt_mode = iris_abypass_switch_proc(pcfg->display, PASS_THROUGH_MODE, false, true); + if (pt_mode) + iris_set_out_frame_rate(pcfg->panel->cur_mode->timing.refresh_rate); + } else if (type == IRIS_CONT_SPLASH_BYPASS_PRELOAD) { + iris_reset_mipi(); + iris_enable(pcfg->panel, NULL); + } + + vfree(opt_arr); +} + +void iris_send_cont_splash(struct dsi_display *display) +{ + struct dsi_panel *panel = display->panel; + struct iris_cfg *pcfg = iris_get_cfg(); + int lightup_opt = iris_lightup_opt_get(); + uint32_t type; + + if (!iris_is_chip_supported()) + return; + + if (panel->is_secondary) + return; + + if (pcfg->ext_clk) { + IRIS_LOGI("%s(), enable ext clk", __func__); + clk_prepare_enable(pcfg->ext_clk); + } + + // Update panel timing from UEFI. + iris_is_resolution_switched(&panel->cur_mode->timing); + type = iris_get_cont_type_with_timing_switch(panel); + + if (lightup_opt & 0x1) + type = IRIS_CONT_SPLASH_NONE; + + mutex_lock(&pcfg->panel->panel_lock); + _iris_send_cont_splash_pkt(type); + mutex_unlock(&pcfg->panel->panel_lock); +} + +int iris_lightoff(struct dsi_panel *panel, + struct dsi_panel_cmd_set *off_cmds) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + int lightup_opt = iris_lightup_opt_get(); + + pcfg2->mipi_pwr_st = false; + + if (!panel || panel->is_secondary) { + IRIS_LOGD("no need to light off for 2nd panel."); + return 0; + } + + if ((lightup_opt & 0x10) == 0) + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; //clear to ABYP mode + + iris_set_cfg_index(DSI_PRIMARY); + + IRIS_LOGI("%s(%d), mode: %s(%d) ---", __func__, __LINE__, + pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE ? "PT" : "ABYP", + pcfg->abypss_ctrl.abypass_mode); + if (off_cmds) { + if (pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE) + iris_pt_send_panel_cmd(panel, off_cmds); + else + iris_dsi_send_cmds(panel, off_cmds->cmds, off_cmds->count, off_cmds->state); + } + iris_quality_setting_off(); + iris_lp_setting_off(); + _iris_clear_aod_state(); + pcfg->panel_pending = 0; + pcfg->iris_initialized = false; + iris_set_pinctrl_state(pcfg, false); + + IRIS_LOGI("%s(%d) ---", __func__, __LINE__); + + return 0; +} + +int iris_disable(struct dsi_panel *panel, struct dsi_panel_cmd_set *off_cmds) +{ + return iris_lightoff(panel, off_cmds); +} + +static void _iris_send_update_opt( + struct iris_update_ipopt *popt, + struct iris_cmd_comp *pasm_comp, uint8_t path) +{ + int32_t ip = 0; + int32_t rc = 0; + struct iris_ctrl_opt ctrl_opt; + + ip = popt->ip; + ctrl_opt.ip = popt->ip; + ctrl_opt.opt_id = popt->opt_new; + ctrl_opt.skip_last = popt->skip_last; + + /*speical deal with lut table*/ + if (_iris_is_lut(ip)) + rc = _iris_send_lut_pkt(&ctrl_opt, pasm_comp, true, path); + else + rc = _iris_send_dtsi_pkt(&ctrl_opt, pasm_comp, path); + + if (rc) { + IRIS_LOGE("%s(), [FATAL ERROR] invalid ip: %#x, opt: %#x", + __func__, + ip, ctrl_opt.opt_id); + } +} + +static void _iris_send_pq_cmds(struct iris_update_ipopt *popt, int ipopt_cnt, uint8_t path) +{ + int32_t i = 0; + struct iris_cmd_comp cmd_comp; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (!popt || !ipopt_cnt) { + IRIS_LOGE("%s(), invalid popt or ipopt_cnt", __func__); + return; + } + + memset(&cmd_comp, 0x00, sizeof(cmd_comp)); + cmd_comp.cmd = pcfg->iris_cmds.iris_cmds_buf; + cmd_comp.link_state = DSI_CMD_SET_STATE_HS; + cmd_comp.cnt = pcfg->iris_cmds.cmds_index; + + for (i = 0; i < ipopt_cnt; i++) + _iris_send_update_opt(&popt[i], &cmd_comp, path); +} + +static int _iris_update_pq_seq(struct iris_update_ipopt *popt, int ipopt_cnt) +{ + int32_t i = 0; + int32_t j = 0; + int32_t ip = 0; + int32_t opt_id = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_ctrl_seq *pseq = _iris_get_ctrl_seq(pcfg); + + for (i = 0; i < ipopt_cnt; i++) { + /*need to update sequence*/ + if (popt[i].opt_new != popt[i].opt_old) { + for (j = 0; j < pseq->cnt; j++) { + ip = pseq->ctrl_opt[j].ip; + opt_id = pseq->ctrl_opt[j].opt_id; + + if (ip == popt[i].ip && + opt_id == popt[i].opt_old) + break; + } + + if (j == pseq->cnt) { + IRIS_LOGE("%s(), failed to find ip: %#x opt: %d", + __func__, + popt[i].ip, popt[i].opt_old); + return -EINVAL; + } + + pseq->ctrl_opt[j].opt_id = popt[i].opt_new; + } + } + + return 0; +} + +void iris_update_pq_opt(struct iris_update_ipopt *popt, int ipopt_cnt, uint8_t path) +{ + int32_t rc = 0; + + if (!popt || !ipopt_cnt) { + IRIS_LOGE("%s(), invalid popt or ipopt_cnt", __func__); + return; + } + + rc = _iris_update_pq_seq(popt, ipopt_cnt); + if (!rc) + _iris_send_pq_cmds(popt, ipopt_cnt, path); +} + +static struct dsi_cmd_desc *_iris_get_desc_from_ipopt(uint8_t ip, uint8_t opt_id, int32_t pos) +{ + struct iris_ip_opt *popt = NULL; + struct iris_cfg *pcfg = NULL; + + pcfg = iris_get_cfg(); + popt = iris_find_ip_opt(ip, opt_id); + if (popt == NULL) { + IRIS_LOGE("%s(), can't find ip opt for ip: 0x%02x, opt: 0x%02x.", + __func__, ip, opt_id); + return NULL; + } + + if (pos < 2) { + IRIS_LOGE("%s(), invalid pos: %d", __func__, pos); + return NULL; + } + + return popt->cmd + (pos * 4 - IRIS_OCP_HEADER_ADDR_LEN) / pcfg->split_pkt_size; +} + +uint32_t *iris_get_ipopt_payload_data( + uint8_t ip, uint8_t opt_id, int32_t pos) +{ + struct dsi_cmd_desc *pdesc = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + + pdesc = _iris_get_desc_from_ipopt(ip, opt_id, pos); + if (!pdesc) { + IRIS_LOGE("%s(), failed to find desc!", __func__); + return NULL; + } else if (pos > pdesc->msg.tx_len) { + IRIS_LOGE("%s(), pos %d is out of paload length %zu", + __func__, + pos, pdesc->msg.tx_len); + return NULL; + } + + return (uint32_t *)((uint8_t *)pdesc->msg.tx_buf + (pos * 4) % pcfg->split_pkt_size); +} + +void iris_set_ipopt_payload_data( + uint8_t ip, uint8_t opt_id, int32_t pos, uint32_t value) +{ + struct dsi_cmd_desc *pdesc = NULL; + struct iris_cfg *pcfg = NULL; + uint32_t *pvalue = NULL; + + pcfg = iris_get_cfg(); + pdesc = _iris_get_desc_from_ipopt(ip, opt_id, pos); + if (!pdesc) { + IRIS_LOGE("%s(), failed to find right desc.", __func__); + return; + } + + pvalue = (uint32_t *)((uint8_t *)pdesc->msg.tx_buf + (pos * 4) % pcfg->split_pkt_size); + pvalue[0] = value; +} + +void iris_update_bitmask_regval_nonread( + struct iris_update_regval *pregval, bool is_commit) +{ + int32_t ip = 0; + int32_t opt_id = 0; + uint32_t orig_val = 0; + uint32_t *data = NULL; + uint32_t val = 0; + struct iris_ip_opt *popt = NULL; + + if (!pregval) { + IRIS_LOGE("%s(), invalid input", __func__); + return; + } + + ip = pregval->ip; + opt_id = pregval->opt_id; + + popt = iris_find_ip_opt(ip, opt_id); + if (popt == NULL) { + IRIS_LOGE("%s(), can't find ip: 0x%02x opt: 0x%02x", + __func__, ip, opt_id); + return; + } else if (popt->cmd_cnt != 1) { + IRIS_LOGE("%s(), invalid bitmask, popt len: %d", + __func__, popt->cmd_cnt); + return; + } + + data = (uint32_t *)popt->cmd[0].msg.tx_buf; + + orig_val = cpu_to_le32(data[2]); + val = orig_val & (~pregval->mask); + val |= (pregval->value & pregval->mask); + data[2] = val; + pregval->value = val; + + if (is_commit) + iris_send_ipopt_cmds(ip, opt_id); +} + +void iris_update_bitmask_regval( + struct iris_update_regval *pregval, bool is_commit) +{ + int32_t ip = 0; + int32_t opt_id = 0; + uint32_t *data = NULL; + struct iris_ip_opt *popt = NULL; + + if (!pregval) { + IRIS_LOGE("%s(), invalid input", __func__); + return; + } + + ip = pregval->ip; + opt_id = pregval->opt_id; + + popt = iris_find_ip_opt(ip, opt_id); + if (popt == NULL) { + IRIS_LOGE("%s(), can't find ip: 0x%02x opt: 0x%02x", + __func__, ip, opt_id); + return; + } else if (popt->cmd_cnt != 2) { + IRIS_LOGE("%s(), invalid bitmask, popt len: %d", + __func__, popt->cmd_cnt); + return; + } + + data = (uint32_t *)popt->cmd[1].msg.tx_buf; + data[2] = cpu_to_le32(pregval->mask); + data[3] = cpu_to_le32(pregval->value); + + if (is_commit) + iris_send_ipopt_cmds(ip, opt_id); +} + +static ssize_t _iris_cont_splash_write( + struct file *file, const char __user *buff, + size_t count, loff_t *ppos) +{ + unsigned long val; + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + _iris_set_cont_splash_type(val); + + if (val == IRIS_CONT_SPLASH_KERNEL) { + struct iris_cfg *pcfg = iris_get_cfg(); + mutex_lock(&pcfg->panel->panel_lock); + _iris_send_cont_splash_pkt(val); + mutex_unlock(&pcfg->panel->panel_lock); + } else if (val != IRIS_CONT_SPLASH_LK && + val != IRIS_CONT_SPLASH_NONE) { + IRIS_LOGE("the value is %zu, need to be 1 or 2 3", val); + } + + return count; +} + +static ssize_t _iris_cont_splash_read( + struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + uint8_t type; + int len, tot = 0; + char bp[512]; + + if (*ppos) + return 0; + + type = iris_get_cont_splash_type(); + len = sizeof(bp); + tot = scnprintf(bp, len, "%u\n", type); + + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + + *ppos += tot; + + return tot; +} + +static const struct file_operations iris_cont_splash_fops = { + .open = simple_open, + .write = _iris_cont_splash_write, + .read = _iris_cont_splash_read, +}; + +static ssize_t _iris_split_pkt_write( + struct file *file, const char __user *buff, + size_t count, loff_t *ppos) +{ + unsigned long val; + struct iris_cfg *pcfg = NULL; + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + pcfg = iris_get_cfg(); + pcfg->add_last_flag = val; + + return count; +} + +static ssize_t _iris_split_pkt_read( + struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + uint8_t type; + int len, tot = 0; + struct iris_cfg *pcfg = NULL; + char bp[512]; + + if (*ppos) + return 0; + + pcfg = iris_get_cfg(); + type = pcfg->add_last_flag; + + len = sizeof(bp); + tot = scnprintf(bp, len, "%u\n", type); + + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + + *ppos += tot; + + return tot; +} + +int iris_wait_vsync(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct drm_encoder *drm_enc; + + if (pcfg->display == NULL || pcfg->display->bridge == NULL)//CID107520 + return -ENOLINK; + drm_enc = pcfg->display->bridge->base.encoder; + if (!drm_enc || !drm_enc->crtc) + return -ENOLINK; + if (sde_encoder_is_disabled(drm_enc)) + return -EIO; + + sde_encoder_wait_for_event(drm_enc, MSM_ENC_VBLANK); + + return 0; +} + +int iris_set_pending_panel_brightness(int32_t pending, int32_t delay, int32_t level) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg) { + IRIS_LOGI("set pending panel %d, %d, %d", pending, delay, level); + pcfg->panel_pending = pending; + pcfg->panel_delay = delay; + pcfg->panel_level = level; + } + + return 0; +} + +int iris_sync_panel_brightness(int32_t step, void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + struct iris_cfg *pcfg; + int rc = 0; + + if (phys_encoder == NULL) + return -EFAULT; + if (phys_encoder->connector == NULL) + return -EFAULT; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return -EFAULT; + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + display = c_conn->display; + if (display == NULL) + return -EFAULT; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg->panel_pending == step) { + IRIS_LOGI("sync pending panel %d %d,%d,%d", + step, pcfg->panel_pending, pcfg->panel_delay, + pcfg->panel_level); + SDE_ATRACE_BEGIN("sync_panel_brightness"); + if (step <= 2) { + rc = c_conn->ops.set_backlight(&c_conn->base, + display, pcfg->panel_level); + usleep_range(pcfg->panel_delay, pcfg->panel_delay + 1); + } else { + usleep_range(pcfg->panel_delay, pcfg->panel_delay + 1); + rc = c_conn->ops.set_backlight(&c_conn->base, + display, pcfg->panel_level); + } + if (c_conn->bl_device) + c_conn->bl_device->props.brightness = pcfg->panel_level; + pcfg->panel_pending = 0; + SDE_ATRACE_END("sync_panel_brightness"); + } + + return rc; +} + +static const struct file_operations iris_split_pkt_fops = { + .open = simple_open, + .write = _iris_split_pkt_write, + .read = _iris_split_pkt_read, +}; + +static ssize_t _iris_chip_id_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + int tot = 0; + struct iris_cfg *pcfg = NULL; + char bp[512]; + + if (*ppos) + return 0; + + pcfg = iris_get_cfg(); + + tot = scnprintf(bp, sizeof(bp), "%u\n", pcfg->chip_id); + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + *ppos += tot; + + return tot; +} + +static const struct file_operations iris_chip_id_fops = { + .open = simple_open, + .read = _iris_chip_id_read, +}; + +static ssize_t _iris_power_mode_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + int tot = 0; + struct iris_cfg *pcfg = NULL; + char bp[512]; + + if (*ppos) + return 0; + + pcfg = iris_get_cfg(); + + tot = scnprintf(bp, sizeof(bp), "0x%02x\n", pcfg->power_mode); + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + *ppos += tot; + + return tot; +} + +static const struct file_operations iris_power_mode_fops = { + .open = simple_open, + .read = _iris_power_mode_read, +}; + +static ssize_t _iris_dbg_i2c_write(struct file *file, const char __user *buff, + size_t count, loff_t *ppos) +{ + + unsigned long val; + int ret = 0; + bool is_ulps_enable = 0; + uint32_t header = 0; + uint32_t arr[100] = {0}; + + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + IRIS_LOGI("%s(%d)", __func__, __LINE__); + + //single write + header = 0xFFFFFFF4; + arr[0] = 0xf0000000; + arr[1] = 0x12345678; + + is_ulps_enable = iris_ulps_enable_get(); + IRIS_LOGI("%s(%d), is_ulps_enable = %d", __func__, __LINE__, is_ulps_enable); + if (is_ulps_enable) + iris_ulps_source_sel(ULPS_NONE); + ret = iris_i2c_ocp_write(arr, 1, 0); + if (is_ulps_enable) + iris_ulps_source_sel(ULPS_MAIN); + if (ret) + IRIS_LOGE("%s(%d), ret = %d", __func__, __LINE__, ret); + + return count; + +} + +static ssize_t _iris_dbg_i2c_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + int ret = 0; + int i = 0; + const int cnt = 5; + const bool is_burst = true; + bool is_ulps_enable = 0; + uint32_t arr[100] = {0}; + + arr[0] = 0xf0000000; + + is_ulps_enable = iris_ulps_enable_get(); + IRIS_LOGI("%s(%d), is_ulps_enable = %d", __func__, __LINE__, is_ulps_enable); + if (is_ulps_enable) + iris_ulps_source_sel(ULPS_NONE); + ret = iris_i2c_ocp_read(arr, cnt, is_burst); + if (is_ulps_enable) + iris_ulps_source_sel(ULPS_MAIN); + + if (ret) { + IRIS_LOGE("%s(%d), ret = %d", __func__, __LINE__, ret); + } else { + for (i = 0; i < cnt; i++) + IRIS_LOGI("%s(%d), arr[%d] = %x", __func__, __LINE__, i, arr[i]); + } + return 0; +} + +static const struct file_operations iris_i2c_srw_fops = { + .open = simple_open, + .write = _iris_dbg_i2c_write, + .read = _iris_dbg_i2c_read, +}; + +static ssize_t _iris_list_debug(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + uint8_t ip; + uint8_t opt_id; + int32_t pos; + uint32_t value; + char buf[64]; + uint32_t *payload = NULL; + + if (count > sizeof(buf)) + return -EINVAL; + + memset(buf, 0, sizeof(buf));//CID98777 + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + if (sscanf(buf, "%x %x %x %x", &ip, &opt_id, &pos, &value) != 4) + return -EINVAL; + + payload = iris_get_ipopt_payload_data(ip, opt_id, 2); + if (payload == NULL) + return -EFAULT; + + IRIS_LOGI("%s: %x %x %x %x", __func__, ip, opt_id, pos, value); + + iris_set_ipopt_payload_data(ip, opt_id, pos, value); + + return count; +} + +static const struct file_operations _iris_list_debug_fops = { + .open = simple_open, + .write = _iris_list_debug, +}; + +static int _iris_dbgfs_cont_splash_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + if (debugfs_create_file("iris_cont_splash", 0644, pcfg->dbg_root, display, + &iris_cont_splash_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("iris_split_pkt", 0644, pcfg->dbg_root, display, + &iris_split_pkt_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("chip_id", 0644, pcfg->dbg_root, display, + &iris_chip_id_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("power_mode", 0644, pcfg->dbg_root, display, + &iris_power_mode_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + debugfs_create_u8("iris_pq_update_path", 0644, pcfg->dbg_root, + (uint8_t *)&iris_pq_update_path); + + if (debugfs_create_file("iris_i2c_srw", 0644, pcfg->dbg_root, display, + &iris_i2c_srw_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("iris_list_debug", 0644, pcfg->dbg_root, display, + &_iris_list_debug_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + return 0; +} + +void iris_prepare(struct dsi_display *display) +{ + int index = display->panel->is_secondary ? DSI_SECONDARY : DSI_PRIMARY; + struct iris_cfg *pcfg = iris_get_cfg_by_index(index); + + if (!iris_is_chip_supported()) + return; + + if (pcfg->valid < PARAM_PARSED) + return; + + iris_frc_prepare(pcfg); + + if (display->panel->is_secondary) + return; + + if (pcfg->valid < PARAM_PREPARED) { + iris_set_cfg_index(index); + iris_parse_lut_cmds(1); + iris_alloc_seq_space(); + pcfg->valid = PARAM_PREPARED; + } +} + +static int _iris_dev_probe(struct platform_device *pdev) +{ + struct iris_cfg *pcfg; + u32 index = 0; + int rc; + + if (!iris_is_chip_supported()) + return 0; + + IRIS_LOGI("%s()", __func__); + if (!pdev || !pdev->dev.of_node) { + IRIS_LOGE("%s(), pdev not found", __func__); + return -ENODEV; + } + + of_property_read_u32_index(pdev->dev.of_node, "index", 0, &index); + pcfg = iris_get_cfg_by_index(index); + pcfg->pdev = pdev; + dev_set_drvdata(&pdev->dev, pcfg); + + rc = iris_enable_pinctrl(pdev, pcfg); + if (rc) { + IRIS_LOGE("%s(), failed to enable pinctrl, return: %d", + __func__, rc); + } + + rc = iris_parse_gpio(pdev, pcfg); + if (rc) { + IRIS_LOGE("%s(), failed to parse gpio, return: %d", + __func__, rc); + return rc; + } + + iris_request_gpio(); + + return 0; +} + +static int _iris_dev_remove(struct platform_device *pdev) +{ + struct iris_cfg *pcfg = dev_get_drvdata(&pdev->dev); + + IRIS_LOGI("%s()", __func__); + if (!iris_is_chip_supported()) + return 0; + + iris_release_gpio(pcfg); + + return 0; +} + +static const struct of_device_id iris_dt_match[] = { + {.compatible = "pxlw,iris"}, + {} +}; + +static struct platform_driver iris_driver = { + .probe = _iris_dev_probe, + .remove = _iris_dev_remove, + .driver = { + .name = "pxlw-iris", + .of_match_table = iris_dt_match, + }, +}; + +module_platform_driver(iris_driver); diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lightup.h b/techpack/display/msm/dsi/iris/dsi_iris5_lightup.h new file mode 100755 index 000000000000..513fc3873369 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lightup.h @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_LIGHTUP_H_ +#define _DSI_IRIS_LIGHTUP_H_ + +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/clk.h> +#include "dsi_pwr.h" +#include "dsi_iris5.h" + +#define IRIS_CHIP_CNT 2 +#define IRIS_PWIL_CUR_META0 0xf12400c8 + +#define MDSS_MAX_PANEL_LEN 256 + +#define HIGH_FREQ 120 +#define LOW_FREQ 60 +#define FHD_H 2376 +#define QHD_H 3168 + + +/* iris ip option, it will create according to opt_id. + * link_state will be create according to the last cmds + */ +struct iris_ip_opt { + uint8_t opt_id; /*option identifier*/ + uint32_t cmd_cnt; /*option length*/ + uint8_t link_state; /*high speed or low power*/ + struct dsi_cmd_desc *cmd; /*the first cmd of desc*/ +}; + +/*ip search index*/ +struct iris_ip_index { + int32_t opt_cnt; /*ip option number*/ + struct iris_ip_opt *opt; /*option array*/ +}; + +struct iris_pq_ipopt_val { + int32_t opt_cnt; + uint8_t ip; + uint8_t *popt; +}; + +struct iris_pq_init_val { + int32_t ip_cnt; + struct iris_pq_ipopt_val *val; +}; + +/*used to control iris_ctrl opt sequence*/ +struct iris_ctrl_opt { + uint8_t ip; + uint8_t opt_id; + uint8_t skip_last; +}; + +struct iris_ctrl_seq { + int32_t cnt; + struct iris_ctrl_opt *ctrl_opt; +}; + +//will pack all the commands here +struct iris_out_cmds { + /* will be used before cmds sent out */ + struct dsi_cmd_desc *iris_cmds_buf; + u32 cmds_index; +}; + +typedef int (*iris_i2c_read_cb)(u32 reg_addr, u32 *reg_val); +typedef int (*iris_i2c_write_cb)(u32 reg_addr, u32 reg_val); +typedef int (*iris_i2c_burst_write_cb)(u32 start_addr, u32 *lut_buffer, u16 reg_num); + +enum IRIS_PARAM_VALID { + PARAM_NONE = 0, + PARAM_EMPTY, + PARAM_PARSED, + PARAM_PREPARED, +}; + +/* iris lightup configure commands */ +struct iris_cfg { + struct dsi_display *display; + struct dsi_panel *panel; + + struct platform_device *pdev; + struct { + struct pinctrl *pinctrl; + struct pinctrl_state *active; + struct pinctrl_state *suspend; + } pinctrl; + int iris_reset_gpio; + int iris_wakeup_gpio; + int iris_abyp_ready_gpio; + int iris_osd_gpio; + int iris_vdd_gpio; + bool iris_osd_autorefresh; + bool iris_osd_autorefresh_enabled; + + /* hardware version and initialization status */ + uint8_t chip_id; + uint32_t chip_ver; + uint32_t chip_value[2]; + uint8_t valid; /* 0: none, 1: empty, 2: parse ok, 3: minimum light up, 4. full light up */ + bool iris_initialized; + bool mcu_code_downloaded; + + /* static configuration */ + uint8_t panel_type; + uint8_t lut_mode; + uint32_t add_last_flag; + uint32_t add_on_last_flag; + uint32_t add_pt_last_flag; + uint32_t split_pkt_size; + uint32_t loop_back_mode; + uint32_t loop_back_mode_res; + struct mutex lb_mutex; + uint32_t min_color_temp; + uint32_t max_color_temp; + uint8_t rx_mode; /* 0: DSI_VIDEO_MODE, 1: DSI_CMD_MODE */ + uint8_t tx_mode; + + /* current state */ + struct iris_lp_ctrl lp_ctrl; + struct iris_abypass_ctrl abypss_ctrl; + uint16_t panel_nits; + uint32_t panel_dimming_brightness; + uint8_t panel_hbm[2]; + bool frc_enable; + bool frc_setting_ready; + struct iris_frc_setting frc_setting; + bool frc_low_latency; + int pwil_mode; + bool osd_enable; + bool osd_on; + bool osd_switch_on_pending; + atomic_t osd_irq_cnt; + uint32_t panel_te; + uint32_t ap_te; + uint32_t switch_mode; + uint8_t power_mode; + bool n2m_enable; + bool mipi_pwr_st; + int dport_output_mode; + bool dynamic_vfr; + atomic_t video_update_wo_osd; + + char display_mode_name[16]; + uint32_t app_version; + uint8_t app_date[4]; + uint8_t abyp_prev_mode; + struct clk *ext_clk; + + uint32_t cmd_list_index; + uint32_t cur_h_active; + uint32_t cur_v_active; + uint32_t switch_case; + int cur_fps_in_iris; //for dynamic fps switch in bypass mode then do switch to pt mode + int next_fps_for_iris; + int cur_vres_in_iris; + + int32_t panel_pending; + int32_t panel_delay; + int32_t panel_level; + + bool aod; + bool fod; + bool fod_pending; + atomic_t fod_cnt; + + struct dsi_regulator_info iris_power_info; // iris pmic power + + /* configuration commands, parsed from dt, dynamically modified + * panel->panel_lock must be locked before access and for DSI command send + */ + uint32_t lut_cmds_cnt; + uint32_t dtsi_cmds_cnt; + struct iris_ip_index ip_index_arr[IRIS_PIP_IDX_CNT][IRIS_IP_CNT]; + struct iris_ctrl_seq ctrl_seq[IRIS_CHIP_CNT]; + struct iris_ctrl_seq ctrl_seq_cs[IRIS_CHIP_CNT]; + struct iris_pq_init_val pq_init_val; + struct iris_out_cmds iris_cmds; + + struct iris_ctrl_seq timing_switch_seq; + struct iris_ctrl_seq timing_switch_seq_1; + + /* one wire gpio lock */ + spinlock_t iris_1w_lock; + struct dentry *dbg_root; + struct work_struct cont_splash_work; + struct work_struct lut_update_work; + struct work_struct vfr_update_work; + struct completion frame_ready_completion; + + /* hook for i2c extension */ + struct mutex gs_mutex; + iris_i2c_read_cb iris_i2c_read; + iris_i2c_write_cb iris_i2c_write; + iris_i2c_burst_write_cb iris_i2c_burst_write; + bool dual_setting; + uint32_t dual_test; +}; + +struct iris_data { + const uint8_t *buf; + uint32_t size; +}; + +struct iris_cfg *iris_get_cfg(void); +struct iris_cfg *iris_get_cfg_by_index(int index); + +int iris_lightup(struct dsi_panel *panel, struct dsi_panel_cmd_set *on_cmds); +int iris_lightoff(struct dsi_panel *panel, struct dsi_panel_cmd_set *off_cmds); +int32_t iris_send_ipopt_cmds(int32_t ip, int32_t opt_id); +void iris_update_pq_opt(struct iris_update_ipopt *popt, int len, uint8_t path); +void iris_update_bitmask_regval( + struct iris_update_regval *pregval, bool is_commit); +void iris_update_bitmask_regval_nonread( + struct iris_update_regval *pregval, bool is_commit); + +void iris_alloc_seq_space(void); + +void iris_init_update_ipopt(struct iris_update_ipopt *popt, + uint8_t ip, uint8_t opt_old, uint8_t opt_new, uint8_t skip_last); +struct iris_pq_ipopt_val *iris_get_cur_ipopt_val(uint8_t ip); + +int iris_init_update_ipopt_t(struct iris_update_ipopt *popt, int len, + uint8_t ip, uint8_t opt_old, uint8_t opt_new, uint8_t skip_last); +struct iris_ip_opt *iris_find_ip_opt(uint8_t ip, uint8_t opt_id); +/* + * @description get assigned position data of ip opt + * @param ip ip sign + * @param opt_id option id of ip + * @param pos the position of option payload + * @return fail NULL/success payload data of position + */ +uint32_t *iris_get_ipopt_payload_data(uint8_t ip, uint8_t opt_id, int32_t pos); +void iris_set_ipopt_payload_data(uint8_t ip, uint8_t opt_id, int32_t pos, uint32_t value); + +/* + *@Description: get current continue splash stage + first light up panel only + second pq effect + */ +uint8_t iris_get_cont_splash_type(void); + +/* + *@Description: print continuous splash commands for bootloader + *@param: pcmd: cmds array cnt: cmds cound + */ +void iris_print_desc_cmds(struct dsi_cmd_desc *pcmd, int cmd_cnt, int state); + +int iris_init_cmds(void); +void iris_get_cmds(struct dsi_panel_cmd_set *cmds, char **ls_arr); +void iris_get_lightoff_cmds(struct dsi_panel_cmd_set *cmds, char **ls_arr); + +int32_t iris_attach_cmd_to_ipidx(const struct iris_data *data, + int32_t data_cnt, struct iris_ip_index *pip_index); + +struct iris_ip_index *iris_get_ip_idx(int32_t type); + +void iris_change_type_addr(struct iris_ip_opt *dest, struct iris_ip_opt *src); + +struct iris_ip_opt *iris_find_ip_opt(uint8_t ip, uint8_t opt_id); + +int iris_wait_vsync(void); +int iris_set_pending_panel_brightness(int32_t pending, int32_t delay, int32_t level); + +bool iris_virtual_display(const struct dsi_display *display); +void iris_free_ipopt_buf(uint32_t ip_type); +void iris_free_seq_space(void); + +void iris_send_assembled_pkt(struct iris_ctrl_opt *arr, int seq_cnt); +int32_t iris_parse_dtsi_cmd(const struct device_node *lightup_node, + uint32_t cmd_index); +int32_t iris_parse_optional_seq(struct device_node *np, const uint8_t *key, + struct iris_ctrl_seq *pseq); + +int iris_display_cmd_engine_enable(struct dsi_display *display); +int iris_display_cmd_engine_disable(struct dsi_display *display); + +#endif // _DSI_IRIS_LIGHTUP_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.c b/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.c new file mode 100755 index 000000000000..e0de0dab0221 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.c @@ -0,0 +1,1585 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <linux/vmalloc.h> +#include <video/mipi_display.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_log.h" + +#define IRIS_TX_HV_PAYLOAD_LEN 120 +#define IRIS_TX_PAYLOAD_LEN 124 +#define IRIS_RD_PACKET_DATA 0xF189C018 +#define IRIS_RD_PACKET_DATA_I3 0xF0C1C018 + +extern int iris_w_path_select; +extern int iris_r_path_select; +static char iris_read_cmd_rbuf[16]; +static struct iris_ocp_cmd ocp_cmd; +static struct iris_ocp_cmd ocp_test_cmd[DSI_CMD_CNT]; +static struct dsi_cmd_desc iris_test_cmd[DSI_CMD_CNT]; + +static void _iris_add_cmd_addr_val( + struct iris_ocp_cmd *pcmd, u32 addr, u32 val) +{ + *(u32 *)(pcmd->cmd + pcmd->cmd_len) = cpu_to_le32(addr); + *(u32 *)(pcmd->cmd + pcmd->cmd_len + 4) = cpu_to_le32(val); + pcmd->cmd_len += 8; +} + +static void _iris_add_cmd_payload(struct iris_ocp_cmd *pcmd, u32 payload) +{ + *(u32 *)(pcmd->cmd + pcmd->cmd_len) = cpu_to_le32(payload); + pcmd->cmd_len += 4; +} + +void iris_ocp_write_val(u32 address, u32 value) +{ + struct iris_ocp_cmd ocp_cmd; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct dsi_cmd_desc iris_ocp_cmd[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0} }; + + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + + _iris_add_cmd_payload(&ocp_cmd, 0xFFFFFFF0 | OCP_SINGLE_WRITE_BYTEMASK); + _iris_add_cmd_addr_val(&ocp_cmd, address, value); + iris_ocp_cmd[0].msg.tx_len = ocp_cmd.cmd_len; + IRIS_LOGD("%s(), addr: 0x%08x, value: 0x%08x", __func__, address, value); + + iris_dsi_send_cmds(pcfg->panel, iris_ocp_cmd, 1, DSI_CMD_SET_STATE_HS); +} + +void iris_ocp_write_vals(u32 header, u32 address, u32 size, u32 *pvalues) +{ + u32 i; + u32 max_size = CMD_PKT_SIZE / 4 - 2; + struct iris_ocp_cmd ocp_cmd; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct dsi_cmd_desc iris_ocp_cmd[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0} }; + + while (size > 0) { + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + + _iris_add_cmd_payload(&ocp_cmd, header); + _iris_add_cmd_payload(&ocp_cmd, address); + if (size < max_size) { + for (i = 0; i < size; i++) + _iris_add_cmd_payload(&ocp_cmd, pvalues[i]); + + size = 0; + } else { + for (i = 0; i < max_size; i++) + _iris_add_cmd_payload(&ocp_cmd, pvalues[i]); + + address += max_size * 4; + pvalues += max_size; + size -= max_size; + } + iris_ocp_cmd[0].msg.tx_len = ocp_cmd.cmd_len; + IRIS_LOGD("%s(), header: 0x%08x, addr: 0x%08x, len: %zu", + __func__, + header, address, iris_ocp_cmd[0].msg.tx_len); + + iris_dsi_send_cmds(pcfg->panel, iris_ocp_cmd, + 1, DSI_CMD_SET_STATE_HS); + } +} + +/*pvalues need to be one address and one value*/ +static void _iris_dsi_write_mult_vals(u32 size, u32 *pvalues) +{ + u32 i; + /*need to remove one header length*/ + u32 max_size = 60; /*(244 -4)/4*/ + u32 header = 0xFFFFFFF4; + struct iris_ocp_cmd ocp_cmd; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct dsi_cmd_desc iris_ocp_cmd[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0} }; + + if (size % 2 != 0) { + IRIS_LOGE("%s(), need to be mult pair of address and value", __func__); + return; + } + + while (size > 0) { + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + + _iris_add_cmd_payload(&ocp_cmd, header); + if (size < max_size) { + for (i = 0; i < size; i++) + _iris_add_cmd_payload(&ocp_cmd, pvalues[i]); + + size = 0; + } else { + for (i = 0; i < max_size; i++) + _iris_add_cmd_payload(&ocp_cmd, pvalues[i]); + + pvalues += max_size; + size -= max_size; + } + iris_ocp_cmd[0].msg.tx_len = ocp_cmd.cmd_len; + IRIS_LOGD("%s(), header: 0x%08x, len: %zu", + __func__, + header, iris_ocp_cmd[0].msg.tx_len); + + iris_dsi_send_cmds(pcfg->panel, iris_ocp_cmd, + 1, DSI_CMD_SET_STATE_HS); + } +} + +static void _iris_i2c_write_mult_vals(u32 size, u32 *pvalues) +{ + int ret = 0; + bool is_burst = 0; + bool is_ulps_enable = 0; + + if (size % 2 != 0) { + IRIS_LOGE("%s(), need to be mult pair of address and value", __func__); + return; + } + + is_ulps_enable = iris_disable_ulps(PATH_I2C); + ret = iris_i2c_ocp_write(pvalues, size / 2, is_burst); + iris_enable_ulps(PATH_I2C, is_ulps_enable); + + if (ret) + IRIS_LOGE("%s(%d), i2c send fail, return: %d", + __func__, __LINE__, ret); +} + +/*pvalues need to be one address and one value*/ +void iris_ocp_write_mult_vals(u32 size, u32 *pvalues) +{ + int path = iris_w_path_select; + + if (path == PATH_I2C) { + IRIS_LOGD("%s(%d), path select i2c", __func__, __LINE__); + _iris_i2c_write_mult_vals(size, pvalues); + } else if (path == PATH_DSI) { + IRIS_LOGD("%s(%d), path select dsi", __func__, __LINE__); + _iris_dsi_write_mult_vals(size, pvalues); + } else { + IRIS_LOGE("%s(%d), path not i2c or dsi, path = %d", + __func__, __LINE__, path); + } +} + +static void _iris_ocp_write_addr(u32 address, u32 mode) +{ + struct iris_ocp_cmd ocp_cmd; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct dsi_cmd_desc iris_ocp_cmd[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0} }; + + /* Send OCP command.*/ + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + _iris_add_cmd_payload(&ocp_cmd, OCP_SINGLE_READ); + _iris_add_cmd_payload(&ocp_cmd, address); + iris_ocp_cmd[0].msg.tx_len = ocp_cmd.cmd_len; + + iris_dsi_send_cmds(pcfg->panel, iris_ocp_cmd, 1, mode); +} + +static u32 _iris_ocp_read_value(u32 mode) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + char pi_read[1] = {0x00}; + struct dsi_cmd_desc pi_read_cmd[] = { + {{0, MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM, MIPI_DSI_MSG_REQ_ACK, + 0, 0, sizeof(pi_read), pi_read, 0, NULL}, 1, 0} }; + u32 response_value; + + /* Read response.*/ + memset(iris_read_cmd_rbuf, 0, sizeof(iris_read_cmd_rbuf)); + pi_read_cmd[0].msg.rx_len = 4; + pi_read_cmd[0].msg.rx_buf = iris_read_cmd_rbuf; + iris_dsi_send_cmds(pcfg->panel, pi_read_cmd, 1, mode); + IRIS_LOGD("read register %02x %02x %02x %02x", + iris_read_cmd_rbuf[0], iris_read_cmd_rbuf[1], + iris_read_cmd_rbuf[2], iris_read_cmd_rbuf[3]); + + response_value = iris_read_cmd_rbuf[0] | (iris_read_cmd_rbuf[1] << 8) | + (iris_read_cmd_rbuf[2] << 16) | (iris_read_cmd_rbuf[3] << 24); + + return response_value; +} + +static u32 _iris_i2c_single_read(u32 address) +{ + u32 arr[2] = {0}; + bool is_burst = 0; + int ret = 0; + bool is_ulps_enable = 0; + + arr[0] = address; + is_ulps_enable = iris_disable_ulps(PATH_I2C); + ret = iris_i2c_ocp_read(arr, 1, is_burst); + iris_enable_ulps(PATH_I2C, is_ulps_enable); + if (ret) { + IRIS_LOGE("%s(%d), i2c ocp single read fail, return: %d", + __func__, __LINE__, ret); + return 0; + } + IRIS_LOGD("%s(), addr: %#x, value: %#x", __func__, address, arr[0]); + + return arr[0]; +} + +static u32 _iris_dsi_ocp_read(u32 address, u32 mode) +{ + u32 value = 0; + + _iris_ocp_write_addr(address, mode); + + value = _iris_ocp_read_value(mode); + IRIS_LOGD("%s(), addr: %#x, value: %#x", __func__, address, value); + + return value; +} + +u32 iris_ocp_read(u32 address, u32 mode) +{ + u32 value = 0; + int path = iris_r_path_select; + + if (path == PATH_I2C) { + IRIS_LOGD("%s(%d), path select i2c", __func__, __LINE__); + value = _iris_i2c_single_read(address); + } else if (path == PATH_DSI) { + IRIS_LOGD("%s(%d), path select dsi", __func__, __LINE__); + value = _iris_dsi_ocp_read(address, mode); + } else { + IRIS_LOGE("%s(%d), path not i2c or dsi, path = %d", + __func__, __LINE__, path); + } + + return value; +} + +static void _iris_dump_packet(u8 *data, int size) +{ + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, data, size, false); +} + +void iris_write_test(struct dsi_panel *panel, u32 iris_addr, + int ocp_type, u32 pkt_size) +{ + union iris_ocp_cmd_header ocp_header; + struct dsi_cmd_desc iris_cmd = { + {0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0}; + + u32 test_value = 0xFFFF0000; + + memset(&ocp_header, 0, sizeof(ocp_header)); + ocp_header.header32 = 0xFFFFFFF0 | ocp_type; + + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + memcpy(ocp_cmd.cmd, &ocp_header.header32, OCP_HEADER); + ocp_cmd.cmd_len = OCP_HEADER; + + switch (ocp_type) { + case OCP_SINGLE_WRITE_BYTEMASK: + case OCP_SINGLE_WRITE_BITMASK: + for (; ocp_cmd.cmd_len <= (pkt_size - 8); ) { + _iris_add_cmd_addr_val(&ocp_cmd, iris_addr, test_value); + test_value++; + } + break; + case OCP_BURST_WRITE: + test_value = 0xFFFF0000; + _iris_add_cmd_addr_val(&ocp_cmd, iris_addr, test_value); + if (pkt_size <= ocp_cmd.cmd_len) + break; + test_value++; + for (; ocp_cmd.cmd_len <= pkt_size - 4;) { + _iris_add_cmd_payload(&ocp_cmd, test_value); + test_value++; + } + break; + default: + break; + } + + IRIS_LOGI("%s(), len: %d, iris addr: %#x, test value: %#x", + __func__, + ocp_cmd.cmd_len, iris_addr, test_value); + iris_cmd.msg.tx_len = ocp_cmd.cmd_len; + + iris_dsi_send_cmds(panel, &iris_cmd, 1, DSI_CMD_SET_STATE_HS); + + if (IRIS_IF_LOGD()) + _iris_dump_packet(ocp_cmd.cmd, ocp_cmd.cmd_len); +} + +void iris_write_test_muti_pkt(struct dsi_panel *panel, + struct iris_ocp_dsi_tool_input *ocp_input) +{ + union iris_ocp_cmd_header ocp_header; + u32 test_value = 0xFF000000; + int cnt = 0; + + u32 iris_addr, ocp_type, pkt_size, total_cnt; + + ocp_type = ocp_input->iris_ocp_type; + test_value = ocp_input->iris_ocp_value; + iris_addr = ocp_input->iris_ocp_addr; + total_cnt = ocp_input->iris_ocp_cnt; + pkt_size = ocp_input->iris_ocp_size; + + memset(iris_test_cmd, 0, sizeof(iris_test_cmd)); + memset(ocp_test_cmd, 0, sizeof(ocp_test_cmd)); + + memset(&ocp_header, 0, sizeof(ocp_header)); + ocp_header.header32 = 0xFFFFFFF0 | ocp_type; + + switch (ocp_type) { + case OCP_SINGLE_WRITE_BYTEMASK: + case OCP_SINGLE_WRITE_BITMASK: + for (cnt = 0; cnt < total_cnt; cnt++) { + memcpy(ocp_test_cmd[cnt].cmd, + &ocp_header.header32, OCP_HEADER); + ocp_test_cmd[cnt].cmd_len = OCP_HEADER; + + test_value = 0xFF000000 | (cnt << 16); + while (ocp_test_cmd[cnt].cmd_len <= (pkt_size - 8)) { + _iris_add_cmd_addr_val(&ocp_test_cmd[cnt], + (iris_addr + cnt * 4), test_value); + test_value++; + } + + iris_test_cmd[cnt].msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + iris_test_cmd[cnt].msg.tx_len = ocp_test_cmd[cnt].cmd_len; + iris_test_cmd[cnt].msg.tx_buf = ocp_test_cmd[cnt].cmd; + } + iris_test_cmd[total_cnt - 1].last_command = true; + break; + case OCP_BURST_WRITE: + for (cnt = 0; cnt < total_cnt; cnt++) { + memcpy(ocp_test_cmd[cnt].cmd, + &ocp_header.header32, OCP_HEADER); + ocp_test_cmd[cnt].cmd_len = OCP_HEADER; + test_value = 0xFF000000 | (cnt << 16); + + _iris_add_cmd_addr_val(&ocp_test_cmd[cnt], + (iris_addr + cnt * 4), test_value); + /* if(pkt_size <= ocp_test_cmd[cnt].cmd_len) + * break; + */ + test_value++; + while (ocp_test_cmd[cnt].cmd_len <= pkt_size - 4) { + _iris_add_cmd_payload(&ocp_test_cmd[cnt], test_value); + test_value++; + } + + iris_test_cmd[cnt].msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + iris_test_cmd[cnt].msg.tx_len = ocp_test_cmd[cnt].cmd_len; + iris_test_cmd[cnt].msg.tx_buf = ocp_test_cmd[cnt].cmd; + } + iris_test_cmd[total_cnt - 1].last_command = true; + break; + default: + break; + } + + IRIS_LOGI("%s(), total count: %#x, iris addr: %#x, test value: %#x", + __func__, total_cnt, iris_addr, test_value); + iris_dsi_send_cmds(panel, iris_test_cmd, total_cnt, DSI_CMD_SET_STATE_HS); + + if (IRIS_IF_NOT_LOGV()) + return; + + for (cnt = 0; cnt < total_cnt; cnt++) + _iris_dump_packet(ocp_test_cmd[cnt].cmd, + ocp_test_cmd[cnt].cmd_len); +} + +int iris_dsi_send_cmds(struct dsi_panel *panel, + struct dsi_cmd_desc *cmds, + u32 count, + enum dsi_cmd_set_state state) +{ + int rc = 0; + int i = 0; + ssize_t len; + const struct mipi_dsi_host_ops *ops; + struct iris_cfg *pcfg = NULL; + struct dsi_display *display = NULL; + + if (!panel || !panel->cur_mode) + return -EINVAL; + + if (count == 0) { + IRIS_LOGD("%s(), panel %s no commands to be sent for state %d", + __func__, + panel->name, state); + goto error; + } + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + display = pcfg->display; + + ops = panel->host->ops; + + 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; + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + WARN_ON(!mutex_is_locked(&panel->panel_lock)); + len = ops->transfer(panel->host, &cmds->msg); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + + if (IRIS_IF_LOGVV()) + _iris_dump_packet((u8 *)cmds->msg.tx_buf, cmds->msg.tx_len); + + if (len < 0) { + rc = len; + IRIS_LOGE("%s(), failed to set cmds: %d, return: %d", + __func__, + cmds->msg.type, rc); + dump_stack(); + 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 u32 _iris_pt_get_split_pkt_cnt(int dlen) +{ + u32 sum = 1; + + if (dlen > IRIS_TX_HV_PAYLOAD_LEN) + sum = (dlen - IRIS_TX_HV_PAYLOAD_LEN + + IRIS_TX_PAYLOAD_LEN - 1) / IRIS_TX_PAYLOAD_LEN + 1; + return sum; +} + +/* + * @Description: use to do statitics for cmds which should not less than 252 + * if the payload is out of 252, it will change to more than one cmds + * the first payload need to be + * 4 (ocp_header) + 8 (tx_addr_header + tx_val_header) + * + 2* payload_len (TX_payloadaddr + payload_len)<= 252 + * the sequence payloader need to be + * 4 (ocp_header) + 2* payload_len (TX_payloadaddr + payload_len)<= 252 + * so the first payload should be no more than 120 + * the second and sequence need to be no more than 124 + * + * @Param: cmdset cmds request + * @return: the cmds number need to split + **/ +static u32 _iris_pt_calc_cmd_cnt(struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u32 sum = 0; + u32 dlen = 0; + + for (i = 0; i < cmdset->count; i++) { + dlen = cmdset->cmds[i].msg.tx_len; + sum += _iris_pt_get_split_pkt_cnt(dlen); + } + + return sum; +} + +static int _iris_pt_alloc_cmds( + struct dsi_panel_cmd_set *cmdset, + struct dsi_cmd_desc **ptx_cmds, + struct iris_ocp_cmd **pocp_cmds) +{ + int cmds_cnt = _iris_pt_calc_cmd_cnt(cmdset); + + IRIS_LOGD("%s(%d), cmds cnt: %d malloc len: %lu", + __func__, __LINE__, + cmds_cnt, cmds_cnt * sizeof(**ptx_cmds)); + *ptx_cmds = vmalloc(cmds_cnt * sizeof(**ptx_cmds)); + if (!(*ptx_cmds)) { + IRIS_LOGE("%s(), failed to malloc buf, len: %lu", + __func__, + cmds_cnt * sizeof(**ptx_cmds)); + return -ENOMEM; + } + + *pocp_cmds = vmalloc(cmds_cnt * sizeof(**pocp_cmds)); + if (!(*pocp_cmds)) { + IRIS_LOGE("%s(), failed to malloc buf for pocp cmds", __func__); + vfree(*ptx_cmds); + *ptx_cmds = NULL; + return -ENOMEM; + } + return cmds_cnt; +} + +static void _iris_pt_init_tx_cmd_hdr( + struct dsi_panel_cmd_set *cmdset, struct dsi_cmd_desc *dsi_cmd, + union iris_mipi_tx_cmd_header *header) +{ + u8 dtype = dsi_cmd->msg.type; + + memset(header, 0x00, sizeof(*header)); + header->stHdr.dtype = dtype; + header->stHdr.linkState = (cmdset->state == DSI_CMD_SET_STATE_LP) ? 1 : 0; +} + +static void _iris_pt_set_cmd_hdr( + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd, bool is_write) +{ + u32 dlen = 0; + u8 *ptr = NULL; + + if (!dsi_cmd) + return; + + dlen = dsi_cmd->msg.tx_len; + + if (is_write) + pheader->stHdr.writeFlag = 0x01; + else + pheader->stHdr.writeFlag = 0x00; + + if (pheader->stHdr.longCmdFlag == 0) { + ptr = (u8 *)dsi_cmd->msg.tx_buf; + if (dlen == 1) { + pheader->stHdr.len[0] = ptr[0]; + } else if (dlen == 2) { + pheader->stHdr.len[0] = ptr[0]; + pheader->stHdr.len[1] = ptr[1]; + } + } else { + pheader->stHdr.len[0] = dlen & 0xff; + pheader->stHdr.len[1] = (dlen >> 8) & 0xff; + } +} + +static void _iris_pt_set_wrcmd_hdr( + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd) +{ + _iris_pt_set_cmd_hdr(pheader, dsi_cmd, true); +} + +static void _iris_pt_set_rdcmd_hdr( + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd) +{ + _iris_pt_set_cmd_hdr(pheader, dsi_cmd, false); +} + +static void _iris_pt_init_ocp_cmd(struct iris_ocp_cmd *pocp_cmd) +{ + union iris_ocp_cmd_header ocp_header; + + if (!pocp_cmd) { + IRIS_LOGE("%s(), invalid pocp cmd!", __func__); + return; + } + + memset(pocp_cmd, 0x00, sizeof(*pocp_cmd)); + ocp_header.header32 = 0xfffffff0 | OCP_SINGLE_WRITE_BYTEMASK; + memcpy(pocp_cmd->cmd, &ocp_header.header32, OCP_HEADER); + pocp_cmd->cmd_len = OCP_HEADER; +} + +static void _iris_add_tx_cmds( + struct dsi_cmd_desc *ptx_cmd, + struct iris_ocp_cmd *pocp_cmd, u8 wait) +{ + struct dsi_cmd_desc desc_init_val = { + {0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, NULL, 0, NULL}, 1, 0}; + + memcpy(ptx_cmd, &desc_init_val, sizeof(struct dsi_cmd_desc)); + ptx_cmd->msg.tx_buf = pocp_cmd->cmd; + ptx_cmd->msg.tx_len = pocp_cmd->cmd_len; + ptx_cmd->post_wait_ms = wait; +} + +static u32 _iris_pt_short_write( + struct iris_ocp_cmd *pocp_cmd, + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd) +{ + u32 sum = 1; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 address = pcfg->chip_ver == IRIS5_CHIP_VERSION ? + IRIS_MIPI_TX_HEADER_ADDR : IRIS_MIPI_TX_HEADER_ADDR_I3; + + pheader->stHdr.longCmdFlag = 0x00; + + _iris_pt_set_wrcmd_hdr(pheader, dsi_cmd); + + IRIS_LOGD("%s(%d), header: 0x%4x", + __func__, __LINE__, + pheader->hdr32); + _iris_add_cmd_addr_val(pocp_cmd, address, pheader->hdr32); + + return sum; +} + +static u32 _iris_pt_short_read( + struct iris_ocp_cmd *pocp_cmd, + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd) +{ + u32 sum = 1; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 address = pcfg->chip_ver == IRIS5_CHIP_VERSION ? + IRIS_MIPI_TX_HEADER_ADDR : IRIS_MIPI_TX_HEADER_ADDR_I3; + + pheader->stHdr.longCmdFlag = 0x00; + _iris_pt_set_rdcmd_hdr(pheader, dsi_cmd); + + IRIS_LOGD("%s(%d), header: 0x%4x", + __func__, __LINE__, + pheader->hdr32); + _iris_add_cmd_addr_val(pocp_cmd, address, pheader->hdr32); + + return sum; +} + +static u32 _iris_pt_get_split_pkt_len(u16 dlen, int sum, int k) +{ + u16 split_len = 0; + + if (k == 0) + split_len = dlen < IRIS_TX_HV_PAYLOAD_LEN + ? dlen : IRIS_TX_HV_PAYLOAD_LEN; + else if (k == sum - 1) + split_len = dlen - IRIS_TX_HV_PAYLOAD_LEN + - (k - 1) * IRIS_TX_PAYLOAD_LEN; + else + split_len = IRIS_TX_PAYLOAD_LEN; + + return split_len; +} + +static void _iris_pt_add_split_pkt_payload( + struct iris_ocp_cmd *pocp_cmd, u8 *ptr, u16 split_len) +{ + u32 i = 0; + union iris_mipi_tx_cmd_payload payload; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 address = pcfg->chip_ver == IRIS5_CHIP_VERSION ? + IRIS_MIPI_TX_PAYLOAD_ADDR : IRIS_MIPI_TX_PAYLOAD_ADDR_I3; + + memset(&payload, 0x00, sizeof(payload)); + for (i = 0; i < split_len; i += 4, ptr += 4) { + if (i + 4 > split_len) { + payload.pld32 = 0; + memcpy(payload.p, ptr, split_len - i); + } else + payload.pld32 = *(u32 *)ptr; + + IRIS_LOGD("%s(), payload: %#x", __func__, payload.pld32); + _iris_add_cmd_addr_val(pocp_cmd, address, + payload.pld32); + } +} + +static u32 _iris_pt_long_write( + struct iris_ocp_cmd *pocp_cmd, + union iris_mipi_tx_cmd_header *pheader, + struct dsi_cmd_desc *dsi_cmd) +{ + u8 *ptr = NULL; + u32 i = 0; + u32 sum = 0; + u16 dlen = 0; + u32 split_len = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 address = pcfg->chip_ver == IRIS5_CHIP_VERSION ? + IRIS_MIPI_TX_HEADER_ADDR : IRIS_MIPI_TX_HEADER_ADDR_I3; + + dlen = dsi_cmd->msg.tx_len; + + pheader->stHdr.longCmdFlag = 0x1; + _iris_pt_set_wrcmd_hdr(pheader, dsi_cmd); + + IRIS_LOGD("%s(%d), header: %#x", + __func__, __LINE__, + pheader->hdr32); + _iris_add_cmd_addr_val(pocp_cmd, address, + pheader->hdr32); + + ptr = (u8 *)dsi_cmd->msg.tx_buf; + sum = _iris_pt_get_split_pkt_cnt(dlen); + + while (i < sum) { + ptr += split_len; + split_len = _iris_pt_get_split_pkt_len(dlen, sum, i); + _iris_pt_add_split_pkt_payload(pocp_cmd + i, ptr, split_len); + + i++; + if (i < sum) + _iris_pt_init_ocp_cmd(pocp_cmd + i); + } + return sum; +} + +static u32 _iris_pt_add_cmd( + struct dsi_cmd_desc *ptx_cmd, struct iris_ocp_cmd *pocp_cmd, + struct dsi_cmd_desc *dsi_cmd, struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u16 dtype = 0; + u32 sum = 0; + u8 wait = 0; + union iris_mipi_tx_cmd_header header; + + _iris_pt_init_tx_cmd_hdr(cmdset, dsi_cmd, &header); + + dtype = dsi_cmd->msg.type; + switch (dtype) { + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + sum = _iris_pt_short_read(pocp_cmd, &header, dsi_cmd); + break; + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_DCS_COMPRESSION_MODE: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + sum = _iris_pt_short_write(pocp_cmd, &header, dsi_cmd); + break; + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_PPS_LONG_WRITE: + sum = _iris_pt_long_write(pocp_cmd, &header, dsi_cmd); + break; + default: + IRIS_LOGE("%s(), invalid type: %#x", + __func__, + dsi_cmd->msg.type); + break; + } + + for (i = 0; i < sum; i++) { + wait = (i == sum - 1) ? dsi_cmd->post_wait_ms : 0; + _iris_add_tx_cmds(ptx_cmd + i, pocp_cmd + i, wait); + } + return sum; +} + +static void _iris_pt_send_cmds( + struct dsi_panel *panel, + struct dsi_cmd_desc *ptx_cmds, u32 cmds_cnt) +{ + struct dsi_panel_cmd_set panel_cmds; + + memset(&panel_cmds, 0x00, sizeof(panel_cmds)); + + panel_cmds.cmds = ptx_cmds; + panel_cmds.count = cmds_cnt; + panel_cmds.state = DSI_CMD_SET_STATE_HS; + iris_dsi_send_cmds(panel, panel_cmds.cmds, + panel_cmds.count, panel_cmds.state); + + if (iris_get_cont_splash_type() == IRIS_CONT_SPLASH_LK) + iris_print_desc_cmds(panel_cmds.cmds, panel_cmds.count, panel_cmds.state); +} + +static void _iris_pt_write_panel_cmd( + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u32 j = 0; + int cmds_cnt = 0; + u32 offset = 0; + struct iris_ocp_cmd *pocp_cmds = NULL; + struct dsi_cmd_desc *ptx_cmds = NULL; + struct dsi_cmd_desc *dsi_cmds = NULL; + + if (!panel || !cmdset) { + IRIS_LOGE("%s(), invalid panel or cmdset!", __func__); + return; + } + + if (cmdset->count == 0) { + IRIS_LOGI("%s(), invalid cmdset count!", __func__); + return; + } + + cmds_cnt = _iris_pt_alloc_cmds(cmdset, &ptx_cmds, &pocp_cmds); + if (cmds_cnt < 0) { + IRIS_LOGE("%s(), invalide cmds count: %d", __func__, cmds_cnt); + return; + } + + for (i = 0; i < cmdset->count; i++) { + /*initial val*/ + dsi_cmds = cmdset->cmds + i; + _iris_pt_init_ocp_cmd(pocp_cmds + j); + offset = _iris_pt_add_cmd( + ptx_cmds + j, pocp_cmds + j, dsi_cmds, cmdset); + j += offset; + } + + if (j != (u32)cmds_cnt) + IRIS_LOGE("%s(), invalid cmd count: %d, j: %d", + __func__, + cmds_cnt, j); + else + _iris_pt_send_cmds(panel, ptx_cmds, (u32)cmds_cnt); + + vfree(pocp_cmds); + vfree(ptx_cmds); + pocp_cmds = NULL; + ptx_cmds = NULL; +} + +static void _iris_pt_switch_cmd( + struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset, + struct dsi_cmd_desc *dsi_cmd) +{ + if (!cmdset || !panel || !dsi_cmd) { + IRIS_LOGE("%s(), invalid input param", __func__); + return; + } + + cmdset->cmds = dsi_cmd; + cmdset->count = 1; +} + +static int _iris_pt_write_max_pkt_size( + struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset) +{ + u32 rlen = 0; + struct dsi_panel_cmd_set local_cmdset; + static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */ + static struct dsi_cmd_desc pkt_size_cmd = { + {0, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, MIPI_DSI_MSG_REQ_ACK, + 0, 0, sizeof(max_pktsize), max_pktsize, 0, NULL}, 1, 0}; + + rlen = cmdset->cmds[0].msg.rx_len; + if (rlen > 128) { + IRIS_LOGE("%s(), invalid len: %d", __func__, rlen); + return -EINVAL; + } + + max_pktsize[0] = (rlen & 0xFF); + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + + _iris_pt_switch_cmd(panel, &local_cmdset, &pkt_size_cmd); + _iris_pt_write_panel_cmd(panel, &local_cmdset); + + return 0; +} + +static void _iris_pt_send_panel_rdcmd( + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + struct dsi_panel_cmd_set local_cmdset; + struct dsi_cmd_desc *dsi_cmd = cmdset->cmds; + + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + + _iris_pt_switch_cmd(panel, &local_cmdset, dsi_cmd); + + /*passthrough write to panel*/ + _iris_pt_write_panel_cmd(panel, &local_cmdset); +} + +static int _iris_pt_remove_respond_hdr(char *ptr, int *offset) +{ + int rc = 0; + char cmd; + + if (!ptr) + return -EINVAL; + + cmd = ptr[0]; + IRIS_LOGV("%s(), cmd: 0x%02x", __func__, cmd); + switch (cmd) { + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: + IRIS_LOGD("%s(), rx ACK_ERR_REPORT", __func__); + rc = -EINVAL; + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: + *offset = 1; + rc = 1; + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: + *offset = 1; + rc = 2; + break; + case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: + case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: + *offset = 4; + rc = ptr[1]; + break; + default: + rc = 0; + } + + return rc; +} + +static void _iris_pt_read(struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u32 rlen = 0; + u32 offset = 0; + union iris_mipi_tx_cmd_payload val; + u8 *rbuf = NULL; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 address = pcfg->chip_ver == IRIS5_CHIP_VERSION ? + IRIS_RD_PACKET_DATA : IRIS_RD_PACKET_DATA_I3; + + rbuf = (u8 *)cmdset->cmds[0].msg.rx_buf; + rlen = cmdset->cmds[0].msg.rx_len; + + if (!rbuf || rlen <= 0) { + IRIS_LOGE("%s(), rbuf: %p, rlen: %d", __func__, rbuf, rlen); + return; + } + + /*read iris for data*/ + val.pld32 = iris_ocp_read(address, cmdset->state); + + rlen = _iris_pt_remove_respond_hdr(val.p, &offset); + IRIS_LOGV("%s(), read len: %d", __func__, rlen); + + if (rlen <= 0) { + IRIS_LOGE("%s(), do not return value", __func__); + return; + } + + if (rlen <= 2) { + for (i = 0; i < rlen; i++) + rbuf[i] = val.p[offset + i]; + } else { + int j = 0; + int len = 0; + int num = (rlen + 3) / 4; + + for (i = 0; i < num; i++) { + len = (i == num - 1) ? rlen - 4 * i : 4; + val.pld32 = iris_ocp_read(address, DSI_CMD_SET_STATE_HS); + for (j = 0; j < len; j++) + rbuf[i * 4 + j] = val.p[j]; + } + } +} + +void iris_pt_read_panel_cmd(struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset) +{ + struct iris_cfg *pcfg = NULL; + struct dsi_display *display = NULL; + + IRIS_LOGD("%s(), enter", __func__); + + if (!panel || !cmdset || cmdset->count != 1) { + IRIS_LOGE("%s(), invalid input, cmdset: %p", __func__, cmdset); + return; + } + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + display = pcfg->display; + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + /*step1 write max packket size*/ + _iris_pt_write_max_pkt_size(panel, cmdset); + + /*step2 write read cmd to panel*/ + _iris_pt_send_panel_rdcmd(panel, cmdset); + + /*step3 read panel data*/ + _iris_pt_read(cmdset); + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); +} + +int iris_pt_send_panel_cmd( + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + if (!cmdset || !panel) { + IRIS_LOGE("%s(), invalid input, cmdset: %p, panel, %p", + __func__, + cmdset, panel); + return -EINVAL; + } + + if (cmdset->count == 1 && cmdset->cmds[0].msg.type == MIPI_DSI_DCS_READ) + iris_pt_read_panel_cmd(panel, cmdset); + else + _iris_pt_write_panel_cmd(panel, cmdset); + + return 0; +} + +void iris_set_pwil_mode(struct dsi_panel *pane, + u8 mode, bool osd_enable, int state) +{ + char pwil_mode[2] = {0x00, 0x00}; + struct dsi_cmd_desc iris_pwil_mode_cmd = { + {0, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM, 0, 0, 0, + sizeof(pwil_mode), pwil_mode, 0, NULL}, 1, 0}; + struct dsi_panel_cmd_set panel_cmds = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &iris_pwil_mode_cmd, + }; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (mode == PT_MODE) { + pwil_mode[0] = 0x0; + pwil_mode[1] = 0x81; + } else if (mode == RFB_MODE) { + pwil_mode[0] = 0xc; + pwil_mode[1] = 0x81; + } else if (mode == FRC_MODE) { + pwil_mode[0] = 0x4; + pwil_mode[1] = 0x82; + } + if (osd_enable) + pwil_mode[0] |= 0x80; + + if (pcfg->panel->cur_mode && pcfg->panel->cur_mode->priv_info && + pcfg->panel->cur_mode->priv_info->dsc_enabled) + pwil_mode[0] |= 0x10; + + IRIS_LOGI("%s(), set pwil mode: %x, %x", __func__, pwil_mode[0], pwil_mode[1]); + + iris_dsi_send_cmds(pcfg->panel, panel_cmds.cmds, + panel_cmds.count, panel_cmds.state); +} + +static int _iris_ctrl_ocp_read_value(struct dsi_display_ctrl *ctrl, + u32 mode, u32 *val) +{ + char pi_read[1] = {0x00}; + struct dsi_cmd_desc pi_read_cmd[] = { + {{0, MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM, MIPI_DSI_MSG_REQ_ACK, + 0, 0, sizeof(pi_read), pi_read, 0, NULL}, 1, 0} }; + u32 response_value; + u32 flags = 0; + int rc = 0; + + /* Read response.*/ + memset(iris_read_cmd_rbuf, 0, sizeof(iris_read_cmd_rbuf)); + pi_read_cmd[0].msg.rx_len = 4; + pi_read_cmd[0].msg.rx_buf = iris_read_cmd_rbuf; + + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ | + DSI_CTRL_CMD_CUSTOM_DMA_SCHED); + flags |= DSI_CTRL_CMD_LAST_COMMAND; + pi_read_cmd->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + if (mode == DSI_CMD_SET_STATE_LP) + pi_read_cmd->msg.flags |= MIPI_DSI_MSG_USE_LPM; + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &pi_read_cmd->msg, &flags); + if (rc <= 0) { + IRIS_LOGE("%s(), rx cmd transfer failed, return: %d", __func__, rc); + return rc; + } + IRIS_LOGD("read register %02x %02x %02x %02x", + iris_read_cmd_rbuf[0], iris_read_cmd_rbuf[1], + iris_read_cmd_rbuf[2], iris_read_cmd_rbuf[3]); + response_value = iris_read_cmd_rbuf[0] | (iris_read_cmd_rbuf[1] << 8) | + (iris_read_cmd_rbuf[2] << 16) | (iris_read_cmd_rbuf[3] << 24); + *val = response_value; + + return 4; +} + +static void _iris_ctrl_ocp_write_addr(struct dsi_display_ctrl *ctrl, + u32 address, + u32 mode) +{ + struct iris_ocp_cmd ocp_cmd; + struct dsi_cmd_desc iris_ocp_cmd[] = { + {{0, MIPI_DSI_GENERIC_LONG_WRITE, 0, 0, 0, + CMD_PKT_SIZE, ocp_cmd.cmd, 0, NULL}, 1, 0} }; + u32 flags = 0; + + /* Send OCP command.*/ + memset(&ocp_cmd, 0, sizeof(ocp_cmd)); + _iris_add_cmd_payload(&ocp_cmd, OCP_SINGLE_READ); + _iris_add_cmd_payload(&ocp_cmd, address); + iris_ocp_cmd[0].msg.tx_len = ocp_cmd.cmd_len; + + flags |= DSI_CTRL_CMD_FETCH_MEMORY; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + iris_ocp_cmd->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + dsi_ctrl_cmd_transfer(ctrl->ctrl, &iris_ocp_cmd->msg, &flags); +} + +static int _iris_ctrl_ocp_read(struct dsi_display_ctrl *ctrl, u32 address, + u32 mode, u32 *pval) +{ + int rc = 0; + + _iris_ctrl_ocp_write_addr(ctrl, address, DSI_CMD_SET_STATE_HS); + rc = _iris_ctrl_ocp_read_value(ctrl, mode, pval); + if (rc != 4) + return -EINVAL; + + return 0; +} + +static int _iris_panel_ctrl_send(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, + struct dsi_cmd_desc *ptx_cmds, u32 cmds_cnt) +{ + u32 flags = 0; + int i; + int rc = 0; + + flags |= DSI_CTRL_CMD_FETCH_MEMORY; + for (i = 0; i < cmds_cnt; i++) { + if (ptx_cmds[i].last_command) { + ptx_cmds[i].msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &ptx_cmds[i].msg, &flags); + if (ptx_cmds[i].post_wait_ms) { + usleep_range(ptx_cmds[i].post_wait_ms * 1000, + ((ptx_cmds[i].post_wait_ms * 1000) + 10)); + IRIS_LOGV("%s(%d), wait: %d ms", __func__, __LINE__, + ptx_cmds[i].post_wait_ms); + } + } + return rc; +} + +static int _iris_panel_ctrl_wr(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u32 j = 0; + int cmds_cnt = 0; + u32 offset = 0; + struct iris_ocp_cmd *pocp_cmds = NULL; + struct dsi_cmd_desc *ptx_cmds = NULL; + struct dsi_cmd_desc *dsi_cmds = NULL; + int rc = 0; + + if (!panel || !cmdset) { + IRIS_LOGE("%s(), invalid input!", __func__); + return -EINVAL; + } + + cmds_cnt = _iris_pt_alloc_cmds(cmdset, &ptx_cmds, &pocp_cmds); + IRIS_LOGV("%s(%d), cmdset.cnt: %d cmds_cnt: %d", __func__, __LINE__, + cmdset->count, cmds_cnt); + if (cmds_cnt < 0) { + IRIS_LOGE("%s(), invalid cmds cnt: %d", __func__, cmds_cnt); + return -ENOMEM; + } + + for (i = 0; i < cmdset->count; i++) { + /*initial val*/ + dsi_cmds = cmdset->cmds + i; + _iris_pt_init_ocp_cmd(pocp_cmds + j); + offset = _iris_pt_add_cmd( + ptx_cmds + j, pocp_cmds + j, dsi_cmds, cmdset); + j += offset; + } + + if (j != (u32)cmds_cnt) { + IRIS_LOGE("%s(), invalid cmds count: %d, j: %d", + __func__, + cmds_cnt, j); + } else { + rc = _iris_panel_ctrl_send(ctrl, panel, ptx_cmds, (u32)cmds_cnt); + } + + vfree(pocp_cmds); + vfree(ptx_cmds); + pocp_cmds = NULL; + ptx_cmds = NULL; + + return rc; +} + +static int _iris_panel_ctrl_pt_read_data(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, + struct dsi_panel_cmd_set *cmdset) +{ + u32 i = 0; + u32 rlen = 0; + u32 offset = 0; + union iris_mipi_tx_cmd_payload val; + u8 *rbuf = NULL; + u32 address = IRIS_RD_PACKET_DATA; + int rc = 0; + + rbuf = (u8 *)cmdset->cmds[0].msg.rx_buf; + rlen = cmdset->cmds[0].msg.rx_len; + + if (!rbuf || rlen <= 0) { + IRIS_LOGE("%s(), rbuf: %p, rlen: %d", __func__, rbuf, rlen); + return -EINVAL; + } + + /* read iris for data */ + rc = _iris_ctrl_ocp_read(ctrl, address, cmdset->state, &val.pld32); + if (rc) { + IRIS_LOGE("%s(), do not return value", __func__); + return -EINVAL; + } + + IRIS_LOGD("%s(%d), rbuf: %p, rlen: %d, pld32: 0x%08x", + __func__, __LINE__, rbuf, rlen, val.pld32); + rlen = _iris_pt_remove_respond_hdr(val.p, &offset); + + if (rlen <= 0) { + IRIS_LOGE("%s(), invalid len: %d", __func__, rlen); + return -EINVAL; + } + + if (rlen <= 2) { + for (i = 0; i < rlen; i++) { + rbuf[i] = val.p[offset + i]; + IRIS_LOGV("%s(%d), rlen: %d, d: 0x%02x", + __func__, __LINE__, rlen, rbuf[i]); + } + } else { + int j = 0; + int len = 0; + int num = (rlen + 3) / 4; + + for (i = 0; i < num; i++) { + len = (i == num - 1) ? rlen - 4 * i : 4; + + rc = _iris_ctrl_ocp_read(ctrl, address, cmdset->state, &val.pld32); + if (rc) { + IRIS_LOGE("%s(), return: %d", __func__, rc); + return -EINVAL; + } + for (j = 0; j < len; j++) { + rbuf[i * 4 + j] = val.p[j]; + IRIS_LOGV("%s(%d), rlen: %d, d: 0x%02x", + __func__, __LINE__, rlen, rbuf[i]); + } + } + } + + return rlen; +} + +static void _iris_panel_ctrl_write_rdcmd(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + struct dsi_panel_cmd_set local_cmdset; + struct dsi_cmd_desc *dsi_cmd = NULL; + + IRIS_LOGD("%s(%d)", __func__, __LINE__); + dsi_cmd = cmdset->cmds; + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + _iris_pt_switch_cmd(panel, &local_cmdset, dsi_cmd); + _iris_panel_ctrl_wr(ctrl, panel, &local_cmdset); +} + +static int _iris_panel_ctrl_set_max_pkt_size(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + int rc = 0; + size_t rlen; + struct dsi_panel_cmd_set local_cmdset; + static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */ + static struct dsi_cmd_desc pkt_size_cmd = { + {0, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, MIPI_DSI_MSG_REQ_ACK, + 0, 0, sizeof(max_pktsize), max_pktsize, 0, NULL}, 1, 0}; + + IRIS_LOGV("%s(%d)", __func__, __LINE__); + rlen = cmdset->cmds[0].msg.rx_len; + if (rlen > 128) { + IRIS_LOGE("%s(), invalid len: %d", __func__, rlen); + return -EINVAL; + } + IRIS_LOGD("%s(), len: %d", __func__, rlen); + + max_pktsize[0] = (rlen & 0xFF); + + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + _iris_pt_switch_cmd(panel, &local_cmdset, &pkt_size_cmd); + local_cmdset.state = DSI_CMD_SET_STATE_HS; + _iris_panel_ctrl_wr(ctrl, panel, &local_cmdset); + + return rc; +} + +static u32 _iris_get_panel_frame_ms(void) +{ + u32 frame = 0; + struct iris_cfg *pcfg = NULL; + struct dsi_display_mode *mode = NULL; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + if (!pcfg || !pcfg->panel || !pcfg->panel->cur_mode) + return 1; + + mode = pcfg->panel->cur_mode; + frame = mode->timing.refresh_rate; + if ((frame < 24) || (frame > 240)) + frame = 24; + + frame = ((1000 / frame) + 1); + + return frame; +} + +static int _iris_panel_ctrl_read(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel, struct dsi_panel_cmd_set *cmdset) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + u32 ms = _iris_get_panel_frame_ms(); + + if (!pcfg) + return rc; + + // step 1: max return size + _iris_panel_ctrl_set_max_pkt_size(ctrl, panel, cmdset); + // step 2: read command + _iris_panel_ctrl_write_rdcmd(ctrl, panel, cmdset); + // step 3: delay one frame + usleep_range(1000 * ms, 1000 * ms + 1); + // step 4: read response data + rc = _iris_panel_ctrl_pt_read_data(ctrl, panel, cmdset); + + return rc; +} + +static int _iris_panel_ctrl_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; + int retry = 3; + + config = &panel->esd_config; + lenp = config->status_valid_params ?: config->status_cmds_rlen; + count = config->status_cmd.count; + cmds = config->status_cmd.cmds; + + for (i = 0; i < count; ++i) { + struct dsi_panel_cmd_set local_cmdset; + + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + memset(config->status_buf, 0x0, SZ_4K); + cmds[i].msg.rx_buf = config->status_buf; + cmds[i].msg.rx_len = config->status_cmds_rlen[i]; + local_cmdset.state = config->status_cmd.state; + _iris_pt_switch_cmd(panel, &local_cmdset, &cmds[i]); + do { + rc = _iris_panel_ctrl_read(ctrl, panel, &local_cmdset); + } while ((rc <= 0) && (--retry)); + if (rc <= 0) { + IRIS_LOGE("%s(), failed for panel ctrl read, return: %d", __func__, rc); + return rc; + } + IRIS_LOGV("%s(%d), status[0]: 0x%02x len: 0x%02x", + __func__, __LINE__, + config->status_buf[0], lenp[i]); + memcpy(config->return_buf + start, + config->status_buf, lenp[i]); + start += lenp[i]; + } + + return 1; +} + +void iris_esd_register_dump(void) +{ + u32 value = 0; + u32 index = 0; + u32 len = 0; + static u32 iris_register_list[] = { + 0xf0000000, + 0xf0000004, + 0xf0000008, + 0xf000001c, + 0xf0000020, + 0xf0000024, + 0xf0000040, + 0xf0000044, + 0xf0000048, + 0xf000004c, + 0xf0000060, + 0xf0000094, + 0xf1800004, + 0xf1800034, + 0xf123ffe4, + 0xf155ffe4, + 0xf1240030, + 0xf125ffe4, + 0xf163ffe4, + 0xf165ffe4, + 0xf169ffe4, + 0xf16bffe4, + 0xf16dffe4, + }; + + IRIS_LOGE("iris esd register dump: "); + len = sizeof(iris_register_list) / sizeof(u32); + for (index = 0; index < len; index++) { + value = iris_ocp_read(iris_register_list[index], + DSI_CMD_SET_STATE_HS); + IRIS_LOGE("%08x : %08x", iris_register_list[index], value); + } +} + +int iris_get_status(void) +{ + int ret = 1; + unsigned int data = 0; + unsigned int reg_update = 0x00; + int cnt = 3; + struct iris_cfg *pcfg; + u32 ms = _iris_get_panel_frame_ms(); + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + if (!pcfg) + return ret; + + if (!pcfg->lp_ctrl.esd_enable) + return 1; + + data = iris_ocp_read(IRIS_REG_INTSTAT_RAW, DSI_CMD_SET_STATE_HS); + if (data & TXFALSE_CONTROL_MASK) { + IRIS_LOGE("INTSTAT_RAW: 0x%x", data); + cnt = 0; + goto status_check_done; + } + IRIS_LOGD("INTSTAT_RAW: 0x%x", data); + + data = iris_ocp_read(IRIS_REG_UPDATE, DSI_CMD_SET_STATE_HS); + iris_ocp_write_val(IRIS_REG_UPDATE, data | (1 << DISP_CMD_SHAWDOW_EN_SHIFT)); + do { + data = iris_ocp_read(IRIS_REG_UPDATE, DSI_CMD_SET_STATE_HS); + reg_update = data & DISP_CMD_SHAWDOW_EN_MASK; + if (!reg_update) { + IRIS_LOGD("esd %d reg_update: 0x%x", cnt, data); + break; + } + IRIS_LOGW("esd %d data: 0x%x reg_update: 0x%x", cnt, data, reg_update); + usleep_range(1000 * ms, 1000 * ms + 1); + } while (--cnt); + +status_check_done: + if (cnt == 0) { + if (pcfg->lp_ctrl.esd_cnt < 10000) + pcfg->lp_ctrl.esd_cnt++; + else + pcfg->lp_ctrl.esd_cnt = 0; + + IRIS_LOGE("esd detected. enable: %d", pcfg->lp_ctrl.esd_enable); + if (pcfg->lp_ctrl.esd_enable) { + IRIS_LOGE("esd recovery"); + iris_esd_register_dump(); + ret = -1; + } + } else { + ret = 1; + } + IRIS_LOGD("%s(), return: %d", __func__, ret); + + return ret; +} + +int iris_read_status(struct dsi_display_ctrl *ctrl, struct dsi_panel *panel) +{ + struct iris_cfg *pcfg; + int ret = 1; + + IRIS_LOGV("%s(%d)", __func__, __LINE__); + if (!panel || !ctrl || !ctrl->ctrl) + return -EINVAL; + + if (!dsi_ctrl_validate_host_state(ctrl->ctrl)) + return 1; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + if (pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) { + IRIS_LOGI("%s(), in bypass mode", __func__); + return 2; + } + + if (1) { + int rc = 0; + + IRIS_LOGI("%s(%d)", __func__, __LINE__); + rc = _iris_panel_ctrl_read_status(ctrl, panel); + if (rc <= 0) + return -EINVAL; + + rc = iris_get_status(); + if (rc <= 0) + return -EINVAL; + + } else { + iris_get_status(); + } + + return ret; +} + +int iris_panel_ctrl_read_reg(struct dsi_display_ctrl *ctrl, struct dsi_panel *panel, + u8 *rx_buf, int rlen, struct dsi_cmd_desc *cmd) +{ + int rc = 0; + int retry = 3; + struct dsi_panel_cmd_set local_cmdset; + struct dsi_cmd_desc *cmds = cmd; + + if (ctrl == NULL || panel == NULL || rx_buf == NULL || cmds == NULL || rlen <= 0) + return -EINVAL; + + memset(&local_cmdset, 0x00, sizeof(local_cmdset)); + cmds->msg.rx_buf = rx_buf; + cmds->msg.rx_len = rlen; + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM; + _iris_pt_switch_cmd(panel, &local_cmdset, cmds); + do { + rc = _iris_panel_ctrl_read(ctrl, panel, &local_cmdset); + } while ((rc <= 0) && (--retry)); + + if (rc <= 0) { + IRIS_LOGE("%s(), failed for panel ctrl read, return: %d", + __func__, rc); + return rc; + } + + return 1; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.h b/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.h new file mode 100755 index 000000000000..eb29e0ae4172 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lightup_ocp.h @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_LIGHTUP_OCP_H_ +#define _DSI_IRIS_LIGHTUP_OCP_H_ + + +#define IRIS_MIPI_TX_HEADER_ADDR 0xF189C010 +#define IRIS_MIPI_TX_PAYLOAD_ADDR 0xF189C014 +#define IRIS_MIPI_TX_HEADER_ADDR_I3 0xF0C1C010 +#define IRIS_MIPI_TX_PAYLOAD_ADDR_I3 0xF0C1C014 +#define IRIS_TOP_PMU_STATUS 0xF0000094 +#define IRIS_ULPS_CTRL 0xF00000C0 + +#define OCP_BURST_WRITE 0x0 +#define OCP_SINGLE_WRITE_BYTEMASK 0x4 +#define OCP_SINGLE_WRITE_BITMASK 0x5 +#define PXLW_DIRECTBUS_WRITE 0xC +#define OCP_SINGLE_READ 0x8 + +#define ULPS_EN_MASK 0x0080 +#define MIPIRX_ULPS_SELECT 0x03 + +#define DMA_TPG_FIFO_LEN 64 + +#define CMD_PKT_SIZE 512 + +#define TEST_ADDR 0xF1240114 + +#define OCP_HEADER 4 /*4bytes */ +#define OCP_MIN_LEN 12 /* 12bytes */ + +#define DSI_CMD_CNT 20 + +struct iris_ocp_burst_header { + u32 ocp_type:4; + u32 reserved:28; +}; + +struct iris_ocp_read_header { + u32 ocp_type:4; + u32 reserved:28; +}; + +struct iris_ocp_single_bytemask_header { + u32 ocp_type:4; + u32 bytemask1:4; + u32 bytemask2:4; + u32 bytemask3:4; + u32 bytemask4:4; + u32 bytemask5:4; + u32 bytemask6:4; + u32 bytemask7:4; +}; + +struct iris_ocp_single_bitmask_header { + u32 ocp_type:4; + u32 reserved:28; +}; + +struct iris_ocp_direct_bus_header { + u16 ocp_type:4; + u16 reserved:12; + u16 slot_select; +}; + +union iris_ocp_cmd_header { + struct iris_ocp_burst_header st_ocp_burst; + struct iris_ocp_read_header st_ocp_rd; + struct iris_ocp_single_bytemask_header st_ocp_bytemask; + struct iris_ocp_single_bitmask_header st_ocp_bitmask; + struct iris_ocp_direct_bus_header st_ocp_directbus; + u32 header32; +}; + + +struct iris_mipi_tx_cmd_hdr { + u8 dtype; + u8 len[2]; // for short command, means parameter1 and parameter2. for long command, means command length + u8 writeFlag:1; //Read = 0, Write =1 + u8 linkState:1; // HS=0, LP =1 + u8 longCmdFlag:1; // short = 0, long =1 + u8 reserved:5; // =0 +}; + +union iris_mipi_tx_cmd_header { + struct iris_mipi_tx_cmd_hdr stHdr; + u32 hdr32; +}; + +union iris_mipi_tx_cmd_payload { + u8 p[4]; + u32 pld32; +}; + +struct iris_ocp_cmd { + char cmd[CMD_PKT_SIZE]; + int cmd_len; +}; + +struct iris_ocp_dsi_tool_input { + __u16 iris_ocp_type; + __u16 iris_ocp_cnt; + __u32 iris_ocp_addr; + __u32 iris_ocp_value; + __u32 iris_ocp_size; +}; + + +void iris_ocp_write_val(u32 address, u32 value); +void iris_ocp_write_vals(u32 header, u32 address, u32 size, u32 *pvalues); +void iris_ocp_write_mult_vals(u32 size, u32 *pvalues); +u32 iris_ocp_read(u32 address, u32 type); +void iris_write_test(struct dsi_panel *panel, u32 iris_addr, int ocp_type, u32 pkt_size); +void iris_write_test_muti_pkt(struct dsi_panel *panel, struct iris_ocp_dsi_tool_input *ocp_input); + +int iris_dsi_send_cmds(struct dsi_panel *panel, struct dsi_cmd_desc *cmds, u32 count, enum dsi_cmd_set_state state); +int iris_i2c_read_panel_data(u32 reg_addr, u32 size, u32 *pvalues); +void iris_set_pwil_mode(struct dsi_panel *pane, u8 mode, bool osd_enable, int state); + +#endif // _DSI_IRIS_LIGHTUP_OCP_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_log.h b/techpack/display/msm/dsi/iris/dsi_iris5_log.h new file mode 100755 index 000000000000..9d8f0f07948e --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_log.h @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +/* This file formats log print for 'iris', by adding 'IRIS_LOG' + * prefix to normal log. + * You can use 'adb shell irisConfig -loglevel' to get current + * log level, and 'adb shell irisConfig -loglevel n' to switch + * current log level, which affected by changing global value + * 'iris_log_level'. + * Log prefix can be redefined in respective module, but it + * affects only for itself. You can redefine it just like this: + * #ifdef IRIS_LOG_PREFIX + * #undef IRIS_LOG_PREFIX + * #define IRIS_LOG_PREFIX "IRIS_LOG_XXX" + * #endif + */ +#ifndef __DSI_IRIS_LOG_H_ +#define __DSI_IRIS_LOG_H_ + +#include <linux/kernel.h> + +#ifndef IRIS_LOG_PREFIX +#define IRIS_LOG_PREFIX "IRIS_LOG" +#endif + +#ifndef IRIS_PR +#define IRIS_PR(TAG, format, ...) \ + pr_err("%s%s " format "\n", IRIS_LOG_PREFIX, TAG, ## __VA_ARGS__) +#endif + +#ifndef IRIS_LOG_IF +#define IRIS_LOG_IF(cond, TAG, ...) \ + do { \ + if (cond) \ + IRIS_PR(TAG, __VA_ARGS__); \ + } while (0) +#endif + +void iris_set_loglevel(int level); +int iris_get_loglevel(void); + +/* Priority: + * IRIS_LOGE > IRIS_LOGW > IRIS_LOGI > IRIS_LOGD > IRIS_LOGV + * Instructions: + * 1. IRIS_LOGE, for error log, it can print always. + * 2. IRIS_LOGW, for warrning log, 'iris_log_level' is 2, so it + * can print always by default. + * 3. IRIS_LOGI, for key info log, 'iris_log_level' is 2, so it + * can print always by default. + * 4. IRIS_LOGD, for debug log, it cann't print unless you set + * 'iris_log_level' to '3' or more greater. + * 5. IRIS_LOGV, for debug log, that with block message or print + * very frequently. You must cautiously to use it, because + * massive log may cause performance degradation. It cann't + * print unless you set 'iris_log_level' to '4' or more + * greater. + */ +#ifndef IRIS_LOGE +#define IRIS_LOGE(...) \ + IRIS_LOG_IF(true, " E", __VA_ARGS__) +#endif + +#ifndef IRIS_LOGW +#define IRIS_LOGW(...) \ + IRIS_LOG_IF(iris_get_loglevel() > 0, " W", __VA_ARGS__) +#endif + +#ifndef IRIS_LOGI +#define IRIS_LOGI(...) \ + IRIS_LOG_IF(iris_get_loglevel() > 1, " I", __VA_ARGS__) +#endif + +#ifndef IRIS_LOGD +#define IRIS_LOGD(...) \ + IRIS_LOG_IF(iris_get_loglevel() > 2, " D", __VA_ARGS__) +#endif + +#ifndef IRIS_LOGV +#define IRIS_LOGV(...) \ + IRIS_LOG_IF(iris_get_loglevel() > 3, " V", __VA_ARGS__) +#endif + +#ifndef IRIS_LOGVV +#define IRIS_LOGVV(...) \ + IRIS_LOG_IF(iris_get_loglevel() > 4, " VV", __VA_ARGS__) +#endif + +#ifndef IRIS_IF_LOGI +#define IRIS_IF_LOGI() ((iris_get_loglevel() > 1) ? true : false) +#endif + +#ifndef IRIS_IF_LOGD +#define IRIS_IF_LOGD() ((iris_get_loglevel() > 2) ? true : false) +#endif + +#ifndef IRIS_IF_LOGV +#define IRIS_IF_LOGV() ((iris_get_loglevel() > 3) ? true : false) +#endif + +#ifndef IRIS_IF_LOGVV +#define IRIS_IF_LOGVV() ((iris_get_loglevel() > 4) ? true : false) +#endif + +#ifndef IRIS_IF_NOT_LOGI +#define IRIS_IF_NOT_LOGI() ((iris_get_loglevel() < 2) ? true : false) +#endif + +#ifndef IRIS_IF_NOT_LOGD +#define IRIS_IF_NOT_LOGD() ((iris_get_loglevel() < 3) ? true : false) +#endif + +#ifndef IRIS_IF_NOT_LOGV +#define IRIS_IF_NOT_LOGV() ((iris_get_loglevel() < 4) ? true : false) +#endif + +#ifndef IRIS_IF_NOT_LOGVV +#define IRIS_IF_NOT_LOGVV() ((iris_get_loglevel() < 5) ? true : false) +#endif + +#ifndef IRIS_LOGI_IF +#define IRIS_LOGI_IF(cond) (((cond) && iris_get_loglevel() > 1) ? true : false) +#endif + +#ifndef IRIS_LOGD_IF +#define IRIS_LOGD_IF(cond) (((cond) && iris_get_loglevel() > 2) ? true : false) +#endif + +#ifndef IRIS_LOGV_IF +#define IRIS_LOGV_IF(cond) (((cond) && iris_get_loglevel() > 3) ? true : false) +#endif + +#ifndef IRIS_LOGVV_IF +#define IRIS_LOGVV_IF(cond) (((cond) && iris_get_loglevel() > 4) ? true : false) +#endif + +#endif /* __DSI_IRIS_LOG_H_ */ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.c b/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.c new file mode 100755 index 000000000000..eedc93826102 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.c @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <drm/drm_mipi_dsi.h> +#include <video/mipi_display.h> +#include <linux/of_gpio.h> +#include <dsi_drm.h> +#include <sde_encoder_phys.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_ioctl.h" +#include "dsi_iris5_lut.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_gpio.h" +#include "dsi_iris5_frc.h" +#include "dsi_iris5_log.h" + +static int iris_i2c_test_verify(void); + +int32_t iris_parse_loopback_info(struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + u32 loop_back_mode = 0; + u32 loop_back_mode_res = 0; + + rc = of_property_read_u32(np, "pxlw,loop-back-mode", &loop_back_mode); + if (!rc) + IRIS_LOGE("get property: pxlw, loop-back-mode: %d", loop_back_mode); + pcfg->loop_back_mode = loop_back_mode; + + rc = of_property_read_u32(np, "pxlw,loop-back-mode-res", &loop_back_mode_res); + if (!rc) + IRIS_LOGE("get property: pxlw, loop-back-mode-res: %d", loop_back_mode_res); + pcfg->loop_back_mode_res = loop_back_mode_res; + + return 0; +} + + +int iris_loop_back_reset(void) +{ + iris_send_one_wired_cmd(IRIS_RESET_SYS); + + return 0; +} + +static u32 addrs[66] = { + 0xf000004c, 0xf000004c, 0xf0000048, 0xf1680008, 0xf16e0008, 0xf1a20044, + 0xf1a40044, 0xf158000c, 0xf1580290, 0xf1560118, 0xf1a00060, 0xf1520058, + 0xf10c0000, 0xf1500404, 0xf12c0000, 0xf12d0000, 0xf1640054, 0xf1200020, + 0xf120002c, 0xf120009c, 0xf1210000, 0xf1240004, 0xf1240008, 0xf124000c, + 0xf1240018, 0xf124003c, 0xf1240074, 0xf1240150, 0xf1240170, 0xf1241004, + 0xf1241084, 0xf1241098, 0xf124109c, 0xf12410b0, 0xf12410e8, 0xf1240000, + 0xf1250000, 0xf1280008, 0xf1280038, 0xf12800c4, 0xf1281004, 0xf1281014, + 0xf1281028, 0xf1290000, 0xf1220000, 0xf1220004, 0xf1220008, 0xf1220014, + 0xf122001c, 0xf1220064, 0xf16400b8, 0xf1a40000, 0xf1a40008, 0xf1a40018, + 0xf1a4001c, 0xf1a40024, 0xf1a40028, 0xf1a4002c, 0xf1500098, 0xf1500000, + 0xf1580000, 0xf1580014, 0xf1580290, 0xf1400024, 0xf140002c, 0xf141ff00 +}; + +static u32 values[66] = { + 0x0c011800, 0x0e019c00, 0x000026a0, 0x00000800, 0x00000800, 0x00001FFF, + 0x00001FFF, 0x00000800, 0x00000001, 0x00003FFF, 0x00010800, 0x00003FFF, + 0x00001484, 0x00000800, 0x0000d04d, 0x00000000, 0x000013ff, 0x020002c3, + 0x0000000a, 0x0000000c, 0x0000000f, 0x00401384, 0x30800065, 0x50208800, + 0x04380438, 0x00000020, 0xffffffff, 0x00000545, 0x00000003, 0x00020888, + 0xe4100010, 0x0000005a, 0x00040000, 0x11210100, 0x0000005a, 0xa0e8000c, + 0x00000100, 0x00000001, 0x04380438, 0x00000003, 0x00020888, 0x0000005a, + 0x00000001, 0x00000004, 0xe0008007, 0x21008801, 0x4780010e, 0x00044100, + 0x20000186, 0x00000002, 0xb46c343c, 0x00037762, 0x00080000, 0x00020003, + 0x00020003, 0x00000019, 0x09800438, 0x00080000, 0x00000000, 0xd0840421, + 0x00010040, 0x00000010, 0x00000002, 0x00020000, 0x00200195, 0x00000101 +}; + +void iris_ocp_i3c_write(u32 addr, u32 value) +{ + u32 values[2]; + + values[0] = addr; + values[1] = value; + + IRIS_LOGD("i3c write, addr = %x, value = %x", addr, value); + iris_i2c_ocp_single_write(values, 1); +} + +u32 iris_ocp_i3c_read(u32 addr, u32 mode) +{ + u32 values[2]; + u32 ret = 0; + + values[0] = addr; + values[1] = mode; + + ret = iris_i2c_ocp_read(values, 1, 0); + if (ret) + pr_err("%s error!\n", __func__); + + return values[0]; +} + +static int iris_i2c_test_verify(void) +{ + int rc = 0; + uint32_t val[10] = {10}; + + val[0] = 0xf001fff8; + rc = iris_i2c_conver_ocp_read(val, 1, false); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, val[0]); + val[0] = 0xf1800000; + iris_i2c_conver_ocp_read(val, 1, false); + val[1] = val[0] | 0x1; + val[0] = 0xf1800000; + iris_i2c_single_conver_ocp_write(val, 1); + rc = iris_i2c_conver_ocp_read(val, 1, false); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, val[0]); + + return rc; + +} + +u32 iris_loop_back_verify(void) +{ + + u32 i, r, g, b; + struct iris_cfg *pcfg; + u32 ret = 0; + u32 standard_rgbsum[3] = {0x40d1a890, 0x318c343c, 0x37839da4}; + + pcfg = iris_get_cfg(); + + IRIS_LOGD("loop back verify!\n"); + + iris_ocp_i3c_write(0xf0000044, 0x00000400); + iris_ocp_i3c_write(0xf00000c0, 0x00000055); + iris_ocp_i3c_write(0xf0000060, 0x0f0303fe); + iris_ocp_i3c_write(0xf0000060, 0x0f0303f6); + iris_ocp_i3c_write(0xf0000060, 0x0f0303fe); + msleep(100); + + //iris_ocp_i3c_write(0xf0000050, 0x00003f00); + iris_ocp_i3c_write(0xf0000004, 0x002a80a9); + iris_ocp_i3c_write(0xf0000008, 0x0010f018); + iris_ocp_i3c_write(0xf0000000, 0x00000081); + iris_ocp_i3c_write(0xf0000000, 0x00000083); + iris_ocp_i3c_write(0xf0000000, 0x00000081); + msleep(10); + iris_ocp_i3c_write(0xf0000050, 0x00000000); + + iris_ocp_i3c_write(0xf120005c, 0x00fffffe); + + for (i = 0; i < 66; i++) + iris_ocp_i3c_write(addrs[i], values[i]); + + msleep(1); + iris_ocp_i3c_write(0xf1200020, 0x02000ac3); + iris_ocp_i3c_write(0xf1210000, 0x3); + msleep(20); + iris_ocp_i3c_write(0xf1200020, 0x020002c3); + + r = iris_ocp_i3c_read(0xf12401a8, DSI_CMD_SET_STATE_HS); + g = iris_ocp_i3c_read(0xf12401ac, DSI_CMD_SET_STATE_HS); + b = iris_ocp_i3c_read(0xf12401b0, DSI_CMD_SET_STATE_HS); + IRIS_LOGD("r = 0x%08x, g = 0x%08x, b = 0x%08x\n", r, g, b); + + if ((r == standard_rgbsum[0]) && (g == standard_rgbsum[1]) && (b == standard_rgbsum[2])) + ret = 0; + else + ret = 3; + + return ret; + +} + +int iris_loop_back_validate(void) +{ + + int rc = 0; + int temp = 0; + struct iris_cfg *pcfg = NULL; + + pcfg = iris_get_cfg(); + + IRIS_LOGI("[%s:%d] loop back test.", __func__, __LINE__); + + rc = iris_loop_back_reset(); + if (rc) { + IRIS_LOGW("[%s:%d] loop back iris reset rc = %d", __func__, __LINE__, rc); + return rc; + } + + msleep(10); + temp = iris_ocp_i3c_read(0xf00000d0, DSI_CMD_SET_STATE_HS); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, temp); + + msleep(10); + + temp = iris_ocp_i3c_read(0xf1800000, DSI_CMD_SET_STATE_HS); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, temp); + temp &= (~0x1); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, temp); + iris_ocp_i3c_write(0xf1800000, temp); + temp = iris_ocp_i3c_read(0xf1800000, DSI_CMD_SET_STATE_HS); + IRIS_LOGD("%s,%d: value = 0x%x", __func__, __LINE__, temp); + + rc = iris_loop_back_verify(); + if (rc) { + IRIS_LOGE("[%s:%d] rc = %d", __func__, __LINE__, rc); + return rc; + } + + rc = iris_i2c_test_verify(); + if (rc) { + IRIS_LOGE("[%s:%d] i2c read rc = %d", __func__, __LINE__, rc); + return rc; + } + + rc = iris_loop_back_reset(); + if (rc) { + IRIS_LOGW("[%s:%d] loop back iris reset rc = %d", __func__, __LINE__, rc); + return rc; + } + + iris_abyp_lp(ABYP_POWER_DOWN_PLL); + + return rc; +} + +static ssize_t _iris_dbg_loop_back_ops(struct file *file, + const char __user *buff, size_t count, loff_t *ppos) +{ + unsigned long val; + uint32_t temp, values[2]; + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + if (val == 0) { + iris_reset(); + IRIS_LOGE("iris reset."); + } else if (val == 1) { + iris_exit_abyp(true); + IRIS_LOGE("iris exit abyp."); + } else if (val == 2) { + iris_ocp_write_val(0xf00000c0, 0x0); + IRIS_LOGE("enable analog bypass."); + } else if (val == 3) { + values[0] = 0xf1800000; + values[1] = 0; + iris_i2c_ocp_read(values, 1, 0); + temp = values[0]; + IRIS_LOGD("%s(%d), value = 0x%x", __func__, __LINE__, temp); + temp &= (~0x1); + IRIS_LOGD("%s(%d), value = 0x%x", __func__, __LINE__, temp); + values[0] = 0xf1800000; + values[1] = temp; + iris_i2c_ocp_single_write(values, 1); + values[0] = 0xf1800000; + values[1] = 0; + iris_i2c_ocp_read(values, 1, 0); + temp = values[0]; + IRIS_LOGD("%s(%d), value = 0x%x", __func__, __LINE__, temp); + IRIS_LOGE("%s(%d), disable mipi rx", __func__, __LINE__); + } else if (val == 4) { + iris_loop_back_verify(); + } else if (val == 5) { + temp = 0x400; + values[0] = 0xf0000044; + values[1] = temp; + iris_i2c_ocp_single_write(values, 1); + IRIS_LOGE("%s(%d), rst dtg!", __func__, __LINE__); + } else if (val == 6) { + temp = 0x55; + IRIS_LOGD("%s(%d), value = 0x%x", __func__, __LINE__, temp); + values[0] = 0xf00000c0; + values[1] = temp; + iris_i2c_ocp_single_write(values, 1); + IRIS_LOGE("%s(%d), disable ulps!", __func__, __LINE__); + } else if (val == 7) { + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x26); + } else { + pr_err("%s(%d), parameter error!", __func__, __LINE__); + } + + return count; +} + +static ssize_t _iris_dbg_loop_back_test(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + int ret = 0; + ktime_t ktime0; + ktime_t ktime1; + uint32_t timeus = 0; + struct iris_cfg *pcfg; + int tot = 0; + char bp[512]; + + if (*ppos) + return 0; + + pcfg = iris_get_cfg(); + + mutex_lock(&pcfg->panel->panel_lock); + ktime0 = ktime_get(); + ret = iris_loop_back_validate(); + ktime1 = ktime_get(); + timeus = (u32) ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + mutex_unlock(&pcfg->panel->panel_lock); + IRIS_LOGI("%s(), spend time %d us, return: %d", __func__, timeus, ret); + + + tot = scnprintf(bp, sizeof(bp), "0x%02x\n", ret); + if (copy_to_user(buff, bp, tot)) + return -EFAULT; + *ppos += tot; + + return tot; + +} + +static const struct file_operations iris_loop_back_fops = { + .open = simple_open, + .write = _iris_dbg_loop_back_ops, + .read = _iris_dbg_loop_back_test, +}; + +int iris_loop_back_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + if (debugfs_create_file("iris_loop_back", 0644, pcfg->dbg_root, display, + &iris_loop_back_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.h b/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.h new file mode 100755 index 000000000000..e916e24ba770 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_loop_back.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_BACK_H_ +#define _DSI_IRIS_BACK_H_ + +int32_t iris_parse_loopback_info(struct device_node *np, struct iris_cfg *pcfg); + +u32 iris_loop_back_verify(void); + +/* API in kernel for recovery mode */ +int iris_loop_back_validate(void); + +int iris_loop_back_init(struct dsi_display *display); + +#endif // _DSI_IRIS_BACK_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lp.c b/techpack/display/msm/dsi/iris/dsi_iris5_lp.c new file mode 100755 index 000000000000..19416c80c9db --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lp.c @@ -0,0 +1,1425 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <drm/drm_bridge.h> +#include <drm/drm_encoder.h> +#include "dsi_drm.h" +#include <sde_encoder.h> +#include <sde_encoder_phys.h> +#include <sde_trace.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_gpio.h" +#include "dsi_iris5_timing_switch.h" +#include "dsi_iris5_log.h" + +#define DEBUG_READ_PMU +#define DEFAULT_ABYP_LP_MODE ABYP_POWER_DOWN_PLL + +static int debug_lp_opt; +extern uint8_t iris_pq_update_path; + +/* abyp light up option (need panel off/on to take effect) + * bit[0]: 0 -- light up with PT, 1 -- light up with ABYP + * bit[1]: 0 -- efuse mode is ABYP, 1 -- efuse mode is PT + * bit[2]: 0 -- use mipi command to switch, 1 -- use GPIO to switch + * bit[3]: 0 -- non force, 1 -- force abyp during panel switch + */ +static int debug_on_opt; + +static bool iris_lce_power; + +static bool iris_bsram_power; /* BSRAM domain power status */ + +#define IRIS_TRACE_FPS 0x01 +#define IRIS_TRACE_CADENCE 0X02 +static int debug_trace_opt; +static int debug_abyp_gpio_status = -1; + +int32_t iris_parse_lp_ctrl(struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + u8 vals[3]; + + rc = of_property_read_u8_array(np, "pxlw,low-power", vals, 3); + if (rc) { + IRIS_LOGE("%s(), failed to find low power property, return: %d", + __func__, rc); + return 0; + } + + pcfg->lp_ctrl.dynamic_power = (bool)vals[0]; + pcfg->lp_ctrl.ulps_lp = (bool)vals[1]; + pcfg->lp_ctrl.abyp_enable = (bool)vals[2]; + IRIS_LOGI("%s(), parse low power info: %d %d %d", + __func__, vals[0], vals[1], vals[2]); + + return rc; +} + +void iris_lp_preinit(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + if (iris_virtual_display(pcfg->display) || pcfg->valid < PARAM_PARSED) + return; + + if (debug_on_opt & 0x1) + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + IRIS_LOGI("%s:%d, pcfg->abypss_ctrl.abypass_mode = %d", __func__, __LINE__, pcfg->abypss_ctrl.abypass_mode); + + iris_init_one_wired(); +} + +/* clear some pmu domains */ +static void iris_clear_pmu(void) +{ + struct iris_update_regval regval; + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + iris_bsram_power = false; + + regval.ip = IRIS_IP_SYS; + regval.opt_id = ID_SYS_PMU_CTRL; + regval.mask = 0x000000b8; /*clear MIPI2, BSRAM, FRC, DSCU */ + regval.value = 0x0; + + iris_update_bitmask_regval_nonread(®val, true); +} + +/* init iris low power */ +void iris_lp_init(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + if (iris_virtual_display(pcfg->display) || pcfg->valid < PARAM_PARSED) + return; + + IRIS_LOGI("lp dynamic_power:%d, ulps_lp:%d, abyp_lp_enable:%d", + pcfg->lp_ctrl.dynamic_power, pcfg->lp_ctrl.ulps_lp, + pcfg->lp_ctrl.abyp_enable); + + if (pcfg->lp_ctrl.dynamic_power) { + IRIS_LOGD(" [%s, %d] open psr_mif osd first address eco.", __func__, __LINE__); + iris_psf_mif_dyn_addr_set(true); + iris_dynamic_power_set(true); + } else { + IRIS_LOGD(" [%s, %d] close psr_mif osd first address eco.", __func__, __LINE__); + iris_psf_mif_dyn_addr_set(false); + } + + iris_clear_pmu(); + + if (pcfg->lp_ctrl.ulps_lp) + iris_ulps_source_sel(ULPS_MAIN); + else + iris_ulps_source_sel(ULPS_NONE); +} + +/*== PMU related APIs ==*/ + +/* dynamic power gating set */ +void iris_dynamic_power_set(bool enable) +{ + struct iris_update_regval regval; + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + regval.ip = IRIS_IP_SYS; + regval.opt_id = ID_SYS_PMU_CTRL; + regval.mask = 0x00000001; + regval.value = (enable ? 0x1 : 0x0); + + if (enable) { + /* 0xf0: read; 0xf1: non-read */ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xf0); + + iris_update_bitmask_regval_nonread(®val, true); + } else { + iris_update_bitmask_regval_nonread(®val, true); + + /* delay for disabling dynamic power gating take effect */ + usleep_range(1000 * 20, 1000 * 20 + 1); + /* 0xf0: read; 0xf1: non-read */ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xf1); + } + + pcfg->lp_ctrl.dynamic_power = enable; + IRIS_LOGE("%s: %d", __func__, enable); +} + +/* dynamic power gating get */ +bool iris_dynamic_power_get(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + return pcfg->lp_ctrl.dynamic_power; +} + +static int iris_pmu_power_set(enum iris_pmu_domain domain_id, bool on) +{ + struct iris_update_regval regval; + struct iris_update_ipopt popt; +#ifdef DEBUG_READ_PMU + uint32_t set_pmu_ctrl, pmu_ctrl; + uint32_t *payload = NULL; + uint32_t reg_pmu_ctrl, top_pmu_status, pmu_status; + int i; +#endif + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + regval.ip = IRIS_IP_SYS; + regval.opt_id = ID_SYS_PMU_CTRL; + regval.mask = domain_id; + regval.value = (on ? domain_id : 0x0); + iris_update_bitmask_regval_nonread(®val, false); + iris_init_update_ipopt(&popt, IRIS_IP_SYS, regval.opt_id, regval.opt_id, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(&popt, 1, path); + iris_enable_ulps(path, is_ulps_enable); + +#ifdef DEBUG_READ_PMU + if ((debug_lp_opt & 0x100) == 0x100) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SYS, ID_SYS_PMU_CTRL, 2); + set_pmu_ctrl = payload[0]; + + reg_pmu_ctrl = iris_ocp_read(REG_ADDR_PMU_CTRL, DSI_CMD_SET_STATE_HS); + + if (reg_pmu_ctrl != set_pmu_ctrl) { + IRIS_LOGE("Err: read pmu ctrl 0x%08x != set_pmu_ctrl 0x%08x", reg_pmu_ctrl, set_pmu_ctrl); + return 2; + } + pmu_ctrl = (reg_pmu_ctrl >> 2) & 0xff; + + for (i = 0; i < 10; i++) { + top_pmu_status = iris_ocp_read(REG_ADDR_PMU_STATUS, DSI_CMD_SET_STATE_HS); + pmu_status = ((top_pmu_status>>8)&0x3) + (((top_pmu_status>>15)&0x1)<<2) + + (((top_pmu_status>>11)&0x1)<<3) + (((top_pmu_status>>10)&0x1)<<4) + + (((top_pmu_status>>12)&0x7)<<5); + IRIS_LOGI("read pmu ctrl 0x%08x top_pmu_status 0x%08x, pmu_status 0x%02x", + reg_pmu_ctrl, top_pmu_status, pmu_status); + + if (pmu_status == pmu_ctrl) + break; + + IRIS_LOGE("Err %d: pmu_status: 0x%08x != pmu_ctrl 0x%02x", i, pmu_status, pmu_ctrl); + usleep_range(1000 * 10, 1000 * 10 + 1); + } + if (i == 10) { + IRIS_LOGE("Err: return!"); + return 3; + } + } +#endif + + return 0; +} + +static bool iris_pmu_power_get(enum iris_pmu_domain domain_id) +{ + uint32_t pmu_ctrl; + uint32_t *payload = NULL; + + payload = iris_get_ipopt_payload_data(IRIS_IP_SYS, ID_SYS_PMU_CTRL, 2); + pmu_ctrl = payload[0]; + return ((pmu_ctrl & domain_id) != 0); +} + +void iris_video_abyp_power(bool on) +{ + struct iris_update_regval regval; + struct iris_update_ipopt popt; + struct iris_cfg *pcfg; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + pcfg = iris_get_cfg(); + + regval.ip = IRIS_IP_SYS; + regval.opt_id = ID_SYS_PMU_CTRL; + regval.mask = 0x40800003; + if (on) + regval.value = (pcfg->lp_ctrl.dynamic_power ? 0x3 : 0x2); + else + regval.value = 0x40800000; /*MIPI0_AUTO_DMA_EN, CORE_DOMAINS_OFF_BY_MIPI_EN*/ + + IRIS_LOGE("%s 0x%x 0x%x", __func__, regval.mask, regval.value); + + iris_update_bitmask_regval_nonread(®val, false); + iris_init_update_ipopt(&popt, IRIS_IP_SYS, regval.opt_id, regval.opt_id, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(&popt, 1, path); + iris_enable_ulps(path, is_ulps_enable); +} + +/* power on & off mipi2 domain */ +int iris_pmu_mipi2_set(bool on) +{ + int rt = 0; + + if (((debug_lp_opt & 0x1) == 0x1) && !on) { + IRIS_LOGI("%s: not power down!", __func__); + return 0; + } + rt = iris_pmu_power_set(MIPI2_PWR, on); + IRIS_LOGI("%s: on - %d, rt - %d", __func__, on, rt); + return rt; +} + +/* power on & off bulksram domain */ +int iris_pmu_bsram_set(bool on) +{ + int rt = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + int i = 0; + + if (((debug_lp_opt & 0x2) == 0x2) && !on) { + IRIS_LOGI("%s: not power down!", __func__); + return 0; + } + if (on != iris_bsram_power) { + struct iris_update_regval regval; + struct iris_update_ipopt popt; + + rt = iris_pmu_power_set(BSRAM_PWR, on); + iris_bsram_power = on; + + regval.ip = IRIS_IP_SYS; + regval.opt_id = ID_SYS_MEM_REPAIR; + regval.mask = 0x330000; + regval.value = (on ? 0x330000 : 0x0); + iris_update_bitmask_regval_nonread(®val, false); + iris_init_update_ipopt(&popt, IRIS_IP_SYS, regval.opt_id, regval.opt_id, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(&popt, 1, path); + iris_enable_ulps(path, is_ulps_enable); + if(on){ + udelay(100); + for(i = 0; i < 10; i++) + iris_pmu_power_set(BSRAM_PWR,on); + } + } else { + IRIS_LOGW("%s: cur %d == on %d", __func__, iris_bsram_power, on); + return 2; + } + IRIS_LOGI("%s: on - %d, rt - %d", __func__, on, rt); + return rt; +} + +bool iris_pmu_bsram_get(void) +{ + return iris_bsram_power; +} + +/* power on & off frc domain */ +int iris_pmu_frc_set(bool on) +{ + int rt = 0; + + if (((debug_lp_opt & 0x4) == 0x4) && !on) { + IRIS_LOGI("%s: not power down!", __func__); + return 0; + } + rt = iris_pmu_power_set(FRC_PWR, on); + IRIS_LOGI("%s: on - %d, rt - %d", __func__, on, rt); + return rt; +} + +bool iris_pmu_frc_get(void) +{ + return iris_pmu_power_get(FRC_PWR); +} + +/* power on & off dsc unit domain */ +int iris_pmu_dscu_set(bool on) +{ + int rt = 0; + + if (((debug_lp_opt & 0x8) == 0x8) && !on) { + IRIS_LOGI("%s: not power down!", __func__); + return 0; + } + rt = iris_pmu_power_set(DSCU_PWR, on); + IRIS_LOGI("%s: on - %d, rt - %d", __func__, on, rt); + return rt; +} + +/* power on & off lce domain */ +int iris_pmu_lce_set(bool on) +{ + int rt = 0; + + if (((debug_lp_opt & 0x10) == 0x10) && !on) { + IRIS_LOGI("%s: not power down!", __func__); + return 0; + } + rt = iris_pmu_power_set(LCE_PWR, on); + iris_lce_power_status_set(on); + + IRIS_LOGI("%s: on - %d, rt - %d", __func__, on, rt); + return rt; +} + +/* lce dynamic pmu mask enable */ +void iris_lce_dynamic_pmu_mask_set(bool enable) +{ + //TODO: compile error + //enable = enable; + enable = false; +} + +void iris_lce_power_status_set(bool enable) +{ + iris_lce_power = enable; + + IRIS_LOGI("%s: %d", __func__, enable); +} + +bool iris_lce_power_status_get(void) +{ + return iris_lce_power; +} + +/* trigger DMA to load */ +void iris_dma_trigger_load(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + /* only effective when dynamic power gating off */ + if (!pcfg->lp_ctrl.dynamic_power) { + if (iris_lce_power_status_get()) + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe1); + else + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe5); + } +} + +void iris_ulps_source_sel(enum iris_ulps_sel ulps_sel) +{ + struct iris_update_regval regval; + struct iris_update_ipopt popt; + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + if ((debug_lp_opt & 0x200) == 0x200) { + IRIS_LOGE("not set ulps source sel: %d", ulps_sel); + return; + } + + regval.ip = IRIS_IP_SYS; + regval.opt_id = 0xf1; + regval.mask = 0x3; + regval.value = ulps_sel; + iris_update_bitmask_regval_nonread(®val, false); + iris_init_update_ipopt(&popt, IRIS_IP_SYS, regval.opt_id, regval.opt_id, 0); + iris_update_pq_opt(&popt, 1, PATH_DSI); + IRIS_LOGD("ulps source sel: %d", ulps_sel); + + if (ulps_sel == ULPS_NONE) + pcfg->lp_ctrl.ulps_lp = false; + else + pcfg->lp_ctrl.ulps_lp = true; +} + +bool iris_ulps_enable_get(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + IRIS_LOGI("ulps ap:%d, iris:%d", + pcfg->display->panel->ulps_feature_enabled, pcfg->lp_ctrl.ulps_lp); + + if (pcfg->display->panel->ulps_feature_enabled && pcfg->lp_ctrl.ulps_lp) + return true; + else + return false; +} + +/* TE delay or EVS delay select. + * 0: TE delay; 1: EVS delay + */ +void iris_te_select(int sel) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SYS, + sel ? 0xe1 : 0xe0, 0x1); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_TX, + sel ? 0xe1 : 0xe0, 0x1); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DTG, + sel ? 0xe1 : 0xe0, 0x0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGD("%s: %s", __func__, (sel ? "EVS delay" : "TE delay")); +} + +/*== Analog bypass related APIs ==*/ + + +static struct drm_encoder *iris_get_drm_encoder_handle(void) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + if (pcfg->display->bridge == NULL || pcfg->display->bridge->base.encoder == NULL) + IRIS_LOGE("Can not get drm encoder"); + + return pcfg->display->bridge->base.encoder; +} + +void iris_sde_encoder_rc_lock(void) +{ + struct drm_encoder *drm_enc = NULL; + + drm_enc = iris_get_drm_encoder_handle(); + + sde_encoder_rc_lock(drm_enc); +} + +void iris_sde_encoder_rc_unlock(void) +{ + struct drm_encoder *drm_enc = NULL; + + drm_enc = iris_get_drm_encoder_handle(); + + sde_encoder_rc_unlock(drm_enc); +} + +/* Switch ABYP by mipi commands + * enter_abyp: true -- Enter ABYP; + * false -- Exit ABYP + */ +static void iris_mipi_abyp_switch(bool enter_abyp) +{ + if (enter_abyp) { + iris_send_ipopt_cmds(IRIS_IP_SYS, 4); + IRIS_LOGD("%s, Enter ABYP.", __func__); + } else { + iris_send_ipopt_cmds(IRIS_IP_SYS, 5); + IRIS_LOGD("%s, Exit ABYP.", __func__); + } +} + +bool iris_fast_cmd_abyp_enter(void) +{ + struct iris_cfg *pcfg; + int i; + int abyp_status_gpio; + ktime_t ktime0; + ktime_t ktime1; + uint32_t timeus; + + pcfg = iris_get_cfg(); + if (debug_lp_opt & 0x400) + ktime0 = ktime_get(); + + IRIS_LOGI("Enter abyp mode start"); + /* HS enter abyp */ + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x8); + udelay(100); + + /* check abyp gpio status */ + for (i = 0; i < 10; i++) { + abyp_status_gpio = iris_check_abyp_ready(); + IRIS_LOGD("%s, ABYP status: %d.", __func__, abyp_status_gpio); + if (abyp_status_gpio == 1) { + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time switch ABYP %d us", timeus); + } + //power off domains, switch clocks mux + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x22); + //power off PLL, gate clocks + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x23); + IRIS_LOGD("ABYP enter LP"); + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time ABYP LP %d us", timeus); + } + + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + break; + } + udelay(3 * 1000); + } + if (abyp_status_gpio == 0) { + IRIS_LOGE("Enter abyp mode Failed!"); + return true; + } + IRIS_LOGI("Enter abyp done"); + return false; +} + +bool iris_fast_cmd_abyp_exit(void) +{ + struct dsi_display *display = NULL; + struct iris_cfg *pcfg; + int abyp_status_gpio; + int next_fps, next_vres; + bool high; + ktime_t ktime0; + ktime_t ktime1; + uint32_t timeus; + + pcfg = iris_get_cfg(); + + display = pcfg->display; + next_fps = pcfg->panel->cur_mode->timing.refresh_rate; + next_vres = pcfg->panel->cur_mode->timing.v_active; + if ((next_fps == HIGH_FREQ) && (next_vres == FHD_H)) + high = true; + else + high = false; + + if (debug_lp_opt & 0x400) + ktime0 = ktime_get(); + + IRIS_LOGI("Exit abyp mode start"); + IRIS_LOGI("cur_fps:%d, cur_vres:%d, next_fps:%d, next_vres:%d, high:%d", + pcfg->cur_fps_in_iris, pcfg->cur_vres_in_iris, next_fps, next_vres, high); + + iris_send_one_wired_cmd(IRIS_POWER_DOWN_MIPI); + udelay(3500); + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + udelay(3500); + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time MIPI off/on %d us", timeus); + } + + if (pcfg->iris_initialized) { + if ((pcfg->cur_fps_in_iris == next_fps) && (pcfg->cur_vres_in_iris == next_vres)) { + //ungate clocks & power on PLLs + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x20); + udelay(100); + //switch clock mux & power on domains + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x21); + //configure MIPI and other domains via DMA + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xE9); + udelay(100); + IRIS_LOGD("configure DMA"); + } else { + //ungate clocks && re-program PLL + iris_send_ipopt_cmds(IRIS_IP_SYS, high ? 0x28:0x27); + udelay(100); + //switch clock mux & power on domains + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x21); + + //configure MIPI Rx + iris_send_ipopt_cmds(IRIS_IP_RX, high ? 0xF2:0xF1); + } + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time ABP send LP command %d us", timeus); + } + + } else { + //ungate clocks, power on MIPI PLL + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x24); + //switch clock mux default + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x25); + IRIS_LOGD("ABYP exit LP default"); + } + + /* exit abyp */ + abyp_status_gpio = iris_exit_abyp(false); + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time switch to PT %d us", timeus); + } + if (abyp_status_gpio == 0) { + if (pcfg->iris_initialized == false) { + iris_lightup(pcfg->panel, NULL); + pcfg->iris_initialized = true; + IRIS_LOGI("%s, light up iris", __func__); + } else { + if (pcfg->cur_vres_in_iris != next_vres) { + //resolution change (may have fps change) + iris_send_timing_switch_pkt(); + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xE9); + udelay(200); + } else if (pcfg->cur_fps_in_iris != next_fps) { + //only fps change + iris_send_ipopt_cmds(IRIS_IP_RX, high ? 0xE1:0xE0); + iris_set_out_frame_rate(next_fps); + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xE9); + udelay(200); + } + iris_send_ipopt_cmds(IRIS_IP_SYS, ID_SYS_PMU_CTRL); + if (debug_lp_opt & 0x400) { + ktime1 = ktime_get(); + timeus = (u32)ktime_to_us(ktime1) - (u32)ktime_to_us(ktime0); + ktime0 = ktime1; + IRIS_LOGI("spend time PT HS commmand %d us", timeus); + } + } + + pcfg->cur_fps_in_iris = next_fps; + pcfg->cur_vres_in_iris = next_vres; + iris_update_frc_fps(pcfg->cur_fps_in_iris & 0xFF); + + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + pcfg->abypss_ctrl.abypass_mode = PASS_THROUGH_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + + IRIS_LOGI("Exit abyp done"); + return true; + } + + IRIS_LOGE("Exit abyp mode Failed!"); + return false; +} + +void iris_video_abyp_enter(void) +{ + //todo: I3C or i2c to save more power (one-wire power down/up sys) + struct iris_cfg *pcfg; + int i; + int abyp_status_gpio; + + pcfg = iris_get_cfg(); + + iris_send_ipopt_cmds(IRIS_IP_RX, ID_RX_ENTER_TTL); + IRIS_LOGI("enter TTL bypass"); + + //disable dynamic power gating, power down other domains + iris_video_abyp_power(false); + IRIS_LOGI("power down other domains"); + + iris_send_one_wired_cmd(IRIS_ENTER_ANALOG_BYPASS); + IRIS_LOGI("enter abyp"); + + /* check abyp gpio status */ + for (i = 0; i < 3; i++) { + udelay(10 * 1000); + abyp_status_gpio = iris_check_abyp_ready(); + IRIS_LOGD("%s(%d), ABYP status: %d.", __func__, __LINE__, abyp_status_gpio); + if (abyp_status_gpio == 1) { + iris_send_one_wired_cmd(IRIS_POWER_DOWN_MIPI); + //IRIS_LOGI("power down mipi"); + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + break; + } + } + //usleep_range(1000 * 40, 1000 * 40 + 1); +} + +void iris_video_abyp_exit(void) +{ + struct iris_cfg *pcfg; + int i; + int abyp_status_gpio; + + pcfg = iris_get_cfg(); + IRIS_LOGI("%s", __func__); + + + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + //IRIS_LOGI("power up mipi"); + udelay(10 * 1000); + + iris_send_one_wired_cmd(IRIS_EXIT_ANALOG_BYPASS); + //IRIS_LOGI("exit abyp"); + + /* check abyp gpio status */ + for (i = 0; i < 3; i++) { + udelay(10 * 1000); + abyp_status_gpio = iris_check_abyp_ready(); + IRIS_LOGI("%s(%d), ABYP status: %d.", __func__, __LINE__, abyp_status_gpio); + if (abyp_status_gpio == 0) { + pcfg->abypss_ctrl.abypass_mode = PASS_THROUGH_MODE; + break; + } + } + + /*power up other domains manually */ + iris_video_abyp_power(true); + IRIS_LOGI("power up other domains"); + usleep_range(1000 * 20, 1000 * 20 + 1); + + /*configure other domains IP via DMA trigger */ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe5); + IRIS_LOGI("write dma to trigger other domains"); + usleep_range(1000 * 40, 1000 * 40 + 1); + + /*enable dynamic power gating if need */ + if (pcfg->lp_ctrl.dynamic_power) { + IRIS_LOGI(" [%s, %d] open psr_mif osd first address eco.", __func__, __LINE__); + iris_psf_mif_dyn_addr_set(true); + iris_dynamic_power_set(true); + } else { + IRIS_LOGI(" [%s, %d] close psr_mif osd first address eco.", __func__, __LINE__); + iris_psf_mif_dyn_addr_set(false); + } + //usleep_range(1000 * 40, 1000 * 40 + 1); + iris_send_ipopt_cmds(IRIS_IP_RX, ID_RX_EXIT_TTL); + IRIS_LOGI("exit TTL bypass"); + //usleep_range(1000 * 40, 1000 * 40 + 1); + +} + +#if 0 +int iris_pt_to_abyp_switch(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int abyp_status_gpio; + int *pswitch_state = &pcfg->abypss_ctrl.abyp_switch_state; + int *pframe_delay = &pcfg->abypss_ctrl.frame_delay; + int ret = false; + + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = ANALOG_BYPASS_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + + switch (*pswitch_state) { + case ANALOG_BYPASS_ENTER_STATE: + /* enter abyp */ + iris_send_ipopt_cmds(IRIS_IP_SYS, 6); + IRIS_LOGI("send enter abyp"); + *pswitch_state = ANALOG_BYPASS_CHECK_STATE; + break; + case ANALOG_BYPASS_CHECK_STATE: + abyp_status_gpio = iris_check_abyp_ready(); + if (abyp_status_gpio == 1) { + iris_send_one_wired_cmd(IRIS_POWER_DOWN_MIPI); + IRIS_LOGD("power down mipi"); + pcfg->abypss_ctrl.abypass_mode = ANALOG_BYPASS_MODE; + IRIS_LOGE("Enter abyp done"); + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + ret = true; + } + break; + default: + break; + } + IRIS_LOGI("%s state: %d, delay: %d", __func__, *pswitch_state, *pframe_delay); + + return ret; +} + +int iris_abyp_to_pt_switch(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int abyp_status_gpio; + int *pswitch_state = &pcfg->abypss_ctrl.abyp_switch_state; + int *pframe_delay = &pcfg->abypss_ctrl.frame_delay; + int ret = false; + + static ktime_t kt0, kt1; + + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = PASS_THROUGH_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + + /*if state switch need delay several video frames*/ + if (*pframe_delay > 1) { + *pframe_delay -= 1; + return ret; + } + if (pcfg->iris_initialized == false) { + /* light up iris */ + int i; + + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + udelay(5000); + iris_mipi_abyp_switch(false); + for (i = 0; i < 10; i++) { + abyp_status_gpio = iris_check_abyp_ready(); + if (abyp_status_gpio == 0) + break; + udelay(5000); + } + if (abyp_status_gpio == 0) { + iris_lightup(pcfg->panel, NULL); + pcfg->iris_initialized = true; + IRIS_LOGI("%s, light up iris", __func__); + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.abypass_mode = PASS_THROUGH_MODE; + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + ret = true; + } + + return ret; + } + + switch (*pswitch_state) { + case POWER_UP_STATE: + kt0 = ktime_get(); + /* exit low power mode */ + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + *pswitch_state = CONFIG_MIPI_STATE; + IRIS_LOGI("power up"); + //udelay(3500); + //iris_mipi_abyp_switch(false); + *pframe_delay = 2; + break; + case CONFIG_MIPI_STATE: + kt0 = ktime_get(); + /* configure MIPI via DMA */ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe9); + *pswitch_state = ANALOG_BYPASS_EXIT_STATE; + IRIS_LOGI("configure mipi"); + *pframe_delay = 1; + break; + + case ANALOG_BYPASS_EXIT_STATE: + /* exit abyp */ + //iris_send_one_wired_cmd(IRIS_EXIT_ANALOG_BYPASS); + iris_mipi_abyp_switch(false); + IRIS_LOGI("send exit abyp"); + *pswitch_state = ANALOG_BYPASS_CHECK_STATE; + break; + case ANALOG_BYPASS_CHECK_STATE: + abyp_status_gpio = iris_check_abyp_ready(); + if (abyp_status_gpio == 0) { + iris_send_ipopt_cmds(IRIS_IP_SYS, ID_SYS_PMU_CTRL); + IRIS_LOGI("set pmu"); + *pswitch_state = CONFIG_DMA_STATE; + } + break; + case CONFIG_DMA_STATE: + iris_send_ipopt_cmds(IRIS_IP_PWIL, 0x51); /*WA force enable PWIL capture*/ + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe5); + IRIS_LOGI("trigger dma"); + *pswitch_state = EXIT_TTL_STATE; + break; + case EXIT_TTL_STATE: + iris_send_ipopt_cmds(IRIS_IP_RX, ID_RX_EXIT_TTL); + IRIS_LOGI("exit TTL bypass"); + IRIS_LOGE("Exit abyp done"); + kt1 = ktime_get(); + IRIS_LOGI("abyp->pt: total_time: %d us", + ((u32) ktime_to_us(kt1) - (u32) ktime_to_us(kt0))); + //mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + pcfg->abypss_ctrl.abypass_mode = PASS_THROUGH_MODE; + //mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + ret = true; + break; + default: + break; + } + IRIS_LOGI("%s state: %d, delay: %d", __func__, *pswitch_state, *pframe_delay); + + return ret; +} +#endif + +/* Switch PT and Bypass mode */ +/* Return: true is PT, false is Bypass */ +bool iris_abypass_switch_proc(struct dsi_display *display, int mode, bool pending, bool first) +{ + struct iris_cfg *pcfg; + bool pt_mode; + int dport_status = 0; + + pcfg = iris_get_cfg(); + pt_mode = (pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE); + + if (!pcfg->lp_ctrl.abyp_enable) { + IRIS_LOGE("abyp is disable!"); + return pt_mode; + } + + if (pcfg->rx_mode != pcfg->tx_mode) { + IRIS_LOGE("abyp can't be supported! rx_mode != tx_mode!"); + return pt_mode; + } + + if (pending) { + mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + pcfg->abypss_ctrl.pending_mode = mode & BIT(0); + mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + return pt_mode; + } + + SDE_ATRACE_BEGIN("iris_abyp_switch"); + mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + dport_status = mode & PQ_SWITCH_MASK; // check pq switch mask + // Check GPIO or mipi inside abyp_enter, abyp_exit + if ((mode & BIT(0)) == ANALOG_BYPASS_MODE) { + if (first) + pcfg->abypss_ctrl.abyp_switch_state = ANALOG_BYPASS_ENTER_STATE; + if (pcfg->rx_mode == DSI_OP_CMD_MODE) { /* command mode */ + pt_mode = iris_fast_cmd_abyp_enter(); + } else { + iris_video_abyp_enter(); + pt_mode = false; + } + } else if ((mode & BIT(0)) == PASS_THROUGH_MODE) { + if (first) + pcfg->abypss_ctrl.abyp_switch_state = POWER_UP_STATE; + if (pcfg->rx_mode == DSI_OP_CMD_MODE) {/* command mode */ + pt_mode = iris_fast_cmd_abyp_exit(); + } else { + iris_video_abyp_exit(); + pt_mode = true; + } + /* Soft Iris switch iris PQ: Close dport after enter PT imediately, + * IrisService will open dport after PQ switch + */ + if (dport_status && pt_mode) + iris_dom_set(0); + } else + IRIS_LOGE("%s: switch mode: %d not supported!", __func__, mode); + mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + SDE_ATRACE_END("iris_abyp_switch"); + + return pt_mode; +} + +void iris_abyp_lp(int mode) +{ + int abyp_status_gpio; + + abyp_status_gpio = iris_check_abyp_ready(); + IRIS_LOGD("%s(%d), ABYP status: %d, lp_mode: %d", + __func__, __LINE__, abyp_status_gpio, mode); + + if (abyp_status_gpio == 1) { + if (mode == ABYP_POWER_DOWN_SYS) + iris_send_one_wired_cmd(IRIS_POWER_DOWN_SYS); + else if (mode == ABYP_POWER_DOWN_MIPI) + iris_send_one_wired_cmd(IRIS_POWER_DOWN_MIPI); + else if (mode == ABYP_POWER_DOWN_PLL) + iris_send_ipopt_cmds(IRIS_IP_SYS, 0x26); + else + IRIS_LOGW("[%s:%d] mode: %d error", __func__, __LINE__, mode); + } else { + IRIS_LOGW("iris is not in ABYP mode"); + } + +} + +int iris_exit_abyp(bool one_wired) +{ + int i = 0; + int abyp_status_gpio; + + /* try to exit abyp */ + if (one_wired) { + iris_send_one_wired_cmd(IRIS_EXIT_ANALOG_BYPASS); + udelay(2000); + } else { + iris_mipi_abyp_switch(false); /* switch by MIPI command */ + udelay(100); + } + IRIS_LOGI("send exit abyp, one_wired:%d.", one_wired); + + /* check abyp gpio status */ + for (i = 0; i < 10; i++) { + abyp_status_gpio = iris_check_abyp_ready(); + IRIS_LOGD("%s, ABYP status: %d.", __func__, abyp_status_gpio); + if (abyp_status_gpio == 0) + break; + udelay(3 * 1000); + } + + return abyp_status_gpio; +} + +int iris_lightup_opt_get(void) +{ + return debug_on_opt; +} + +void iris_lp_setting_off(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->abypss_ctrl.pending_mode = MAX_MODE; +} + +#define CHECK_KICKOFF_FPS_CADNENCE +#if defined(CHECK_KICKOFF_FPS_CADNENCE) +int getFrameDiff(long timeDiff) +{ + int frameDiff; + + if (timeDiff < 11) // 16.7-5 ms + frameDiff = 0; + else if (timeDiff < 28) // 33.3-5 + frameDiff = 1; + else if (timeDiff < 45) // 50-5 + frameDiff = 2; + else if (timeDiff < 61) // 66.7-5 + frameDiff = 3; + else if (timeDiff < 78) // 83.3-5 + frameDiff = 4; + else if (timeDiff < 95) // 100 - 5 + frameDiff = 5; + else if (timeDiff < 111) // 116.7 - 5 + frameDiff = 6; + else + frameDiff = 7; + return frameDiff; +} + +#define CHECK_KICKOFF_FPS_DURATION 5 /*EVERY 5s*/ + +void iris_check_kickoff_fps_cadence(void) +{ + static u32 kickoff_cnt; + u32 timeusDelta = 0; + static ktime_t ktime_kickoff_start; + static u32 us_last_kickoff; + ktime_t ktime_kickoff; + static u32 cadence[10]; + static int cdIndex; + u32 us_timediff; + + if (kickoff_cnt == 0) { + kickoff_cnt++; + ktime_kickoff_start = ktime_get(); + memset(cadence, 0, sizeof(cadence)); + cdIndex = 0; + cadence[cdIndex++] = 0; + us_last_kickoff = (u32)ktime_to_us(ktime_kickoff_start); + } else { + kickoff_cnt++; + ktime_kickoff = ktime_get(); + timeusDelta = (u32)ktime_to_us(ktime_kickoff) - (u32)ktime_to_us(ktime_kickoff_start); + us_timediff = (u32)ktime_to_us(ktime_kickoff) - us_last_kickoff; + us_last_kickoff = (u32)ktime_to_us(ktime_kickoff); + if (cdIndex > 9) + cdIndex = 0; + + cadence[cdIndex++] = getFrameDiff((us_timediff+500)/1000);//16667 + if (timeusDelta > 1000000*CHECK_KICKOFF_FPS_DURATION) { + if ((debug_trace_opt&IRIS_TRACE_FPS) == IRIS_TRACE_FPS) + IRIS_LOGI("iris: kickoff fps % d", kickoff_cnt/CHECK_KICKOFF_FPS_DURATION); + if ((debug_trace_opt&IRIS_TRACE_CADENCE) == IRIS_TRACE_CADENCE) + IRIS_LOGI("iris: Latest cadence: %d %d %d %d %d, %d %d %d %d %d", + cadence[0], cadence[1], cadence[2], cadence[3], cadence[4], + cadence[5], cadence[6], cadence[7], cadence[8], cadence[9]); + kickoff_cnt = 0; + } + } +} +#endif + +int iris_prepare_for_kickoff(void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + struct iris_cfg *pcfg; + int mode; + + if (phys_encoder == NULL) + return -EFAULT; + if (phys_encoder->connector == NULL) + return -EFAULT; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return -EFAULT; + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + display = c_conn->display; + if (display == NULL) + return -EFAULT; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + if (iris_virtual_display(display) || pcfg->valid < PARAM_PARSED) + return 0; + +#if defined(CHECK_KICKOFF_FPS_CADNENCE) + if (debug_trace_opt > 0) + iris_check_kickoff_fps_cadence(); +#endif + mutex_lock(&pcfg->abypss_ctrl.abypass_mutex); + if (pcfg->abypss_ctrl.pending_mode != MAX_MODE) { + mode = pcfg->abypss_ctrl.pending_mode; + pcfg->abypss_ctrl.pending_mode = MAX_MODE; + mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + mutex_lock(&pcfg->panel->panel_lock); + iris_abypass_switch_proc(pcfg->display, mode, false, false); + mutex_unlock(&pcfg->panel->panel_lock); + } else + mutex_unlock(&pcfg->abypss_ctrl.abypass_mutex); + + return 0; +} + +void iris_power_up_mipi(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct dsi_display *display = pcfg->display; + + if (iris_virtual_display(display)) + return; + + IRIS_LOGI("%s(%d), power up mipi", __func__, __LINE__); + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + udelay(3500); +} + +void iris_reset_mipi(void) +{ + iris_send_one_wired_cmd(IRIS_POWER_DOWN_MIPI); + IRIS_LOGI("%s(%d), power down mipi", __func__, __LINE__); + udelay(3500); + + iris_send_one_wired_cmd(IRIS_POWER_UP_MIPI); + IRIS_LOGI("%s(%d), power up mipi", __func__, __LINE__); + udelay(3500); +} + +int iris_get_abyp_mode(struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct iris_cfg *pcfg2 = iris_get_cfg_by_index(DSI_SECONDARY); + + IRIS_LOGD("%s(%d), secondary: %d abyp mode: %d, %d", + __func__, __LINE__, + panel->is_secondary, + pcfg->abypss_ctrl.abypass_mode, + pcfg2->abypss_ctrl.abypass_mode); + return (!panel->is_secondary) ? + pcfg->abypss_ctrl.abypass_mode : pcfg2->abypss_ctrl.abypass_mode; +} + + +/*== Low Power debug related ==*/ + +static ssize_t iris_abyp_dbg_write(struct file *file, + const char __user *buff, size_t count, loff_t *ppos) +{ + unsigned long val; + struct iris_cfg *pcfg; + static int cnt; + + pcfg = iris_get_cfg(); + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + if (val == 0) { + iris_fast_cmd_abyp_exit(); + IRIS_LOGI("abyp->pt, %d", cnt); + } else if (val == 1) { + iris_fast_cmd_abyp_enter(); + IRIS_LOGI("pt->abyp, %d", cnt); + } else if (val == 2) { + iris_video_abyp_enter(); + } else if (val == 3) { + iris_video_abyp_exit(); + } else if (val >= 11 && val <= 19) { + IRIS_LOGI("%s one wired %d", __func__, (int)(val - 10)); + iris_send_one_wired_cmd((int)(val - 10)); + } else if (val == 20) { + iris_send_ipopt_cmds(IRIS_IP_SYS, 5); + IRIS_LOGI("miniPMU abyp->pt"); + } else if (val == 21) { + iris_send_ipopt_cmds(IRIS_IP_SYS, 4); + IRIS_LOGI("miniPMU pt->abyp"); + } else if (val == 22) { + iris_send_ipopt_cmds(IRIS_IP_TX, 4); + IRIS_LOGI("Enable Tx"); + } else if (val == 23) { + // mutex_lock(&g_debug_mfd->switch_lock); + iris_lightup(pcfg->panel, &(pcfg->panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_ABYP])); + // mutex_unlock(&g_debug_mfd->switch_lock); + IRIS_LOGI("lightup Iris abyp_panel_cmds"); + } else if (val == 24) { + iris_abypass_switch_proc(pcfg->display, PASS_THROUGH_MODE, false, true); + } else if (val == 25) { + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + } else if (val == 100) { + debug_abyp_gpio_status = iris_check_abyp_ready(); + } + + return count; +} + +static ssize_t iris_lp_dbg_write(struct file *file, + const char __user *buff, size_t count, loff_t *ppos) +{ + unsigned long val; + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + if (val == 0) { + iris_dynamic_power_set(false); + iris_ulps_source_sel(ULPS_NONE); + IRIS_LOGE("disable dynamic & ulps low power."); + } else if (val == 1) { + iris_dynamic_power_set(true); + iris_ulps_source_sel(ULPS_MAIN); + IRIS_LOGE("enable dynamic & ulps low power."); + } else if (val == 2) { + IRIS_LOGE("dynamic power: %d", iris_dynamic_power_get()); + IRIS_LOGE("abyp enable: %d", pcfg->lp_ctrl.abyp_enable); + IRIS_LOGE("ulps enable: %d", iris_ulps_enable_get()); + } else if (val == 3) { + pcfg->lp_ctrl.abyp_enable = true; + IRIS_LOGE("enable abyp."); + } else if (val == 4) { + pcfg->lp_ctrl.abyp_enable = false; + IRIS_LOGE("disable abyp."); + } else if (val == 5) { + iris_ulps_source_sel(ULPS_MAIN); + IRIS_LOGE("enable iris ulps lp."); + } else if (val == 6) { + iris_ulps_source_sel(ULPS_NONE); + IRIS_LOGE("disable iris ulps lp."); + } else if (val == 11) { + iris_pmu_mipi2_set(true); + } else if (val == 12) { + iris_pmu_mipi2_set(false); + } else if (val == 13) { + iris_pmu_bsram_set(true); + } else if (val == 14) { + iris_pmu_bsram_set(false); + } else if (val == 15) { + iris_pmu_frc_set(true); + } else if (val == 16) { + iris_pmu_frc_set(false); + } else if (val == 17) { + iris_pmu_dscu_set(true); + } else if (val == 18) { + iris_pmu_dscu_set(false); + } else if (val == 19) { + iris_pmu_lce_set(true); + } else if (val == 20) { + iris_pmu_lce_set(false); + } else if (val == 254) { + IRIS_LOGI("lp_opt usages:"); + IRIS_LOGI("bit 0 -- MIPI2"); + IRIS_LOGI("bit 1 -- BSRAM"); + IRIS_LOGI("bit 2 -- FRC"); + IRIS_LOGI("bit 3 -- DSCU"); + IRIS_LOGI("bit 4 -- LCE"); + } else if (val == 255) { + IRIS_LOGI("lp debug usages:"); + IRIS_LOGI("0 -- disable dynamic & ulps low power."); + IRIS_LOGI("1 -- enable dynamic & ulps low power."); + IRIS_LOGI("2 -- show low power flag."); + IRIS_LOGI("3 -- enable abyp."); + IRIS_LOGI("4 -- disable abyp."); + IRIS_LOGI("11 -- enable mipi2 power."); + IRIS_LOGI("12 -- disable mipi2 power."); + IRIS_LOGI("13 -- enable bsram power."); + IRIS_LOGI("14 -- disable bram power."); + IRIS_LOGI("15 -- enable frc power."); + IRIS_LOGI("16 -- disable frc power."); + IRIS_LOGI("17 -- enable dsc unit power."); + IRIS_LOGI("18 -- disable dsc unit power."); + IRIS_LOGI("19 -- enable lce power."); + IRIS_LOGI("20 -- disable lce power."); + IRIS_LOGI("254 -- show lp_opt usages."); + IRIS_LOGI("255 -- show debug usages."); + } + return count; +} + +int iris_dbgfs_lp_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg; + static const struct file_operations iris_abyp_dbg_fops = { + .open = simple_open, + .write = iris_abyp_dbg_write, + }; + + static const struct file_operations iris_lp_dbg_fops = { + .open = simple_open, + .write = iris_lp_dbg_write, + }; + + pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + debugfs_create_u32("lp_opt", 0644, pcfg->dbg_root, + (u32 *)&debug_lp_opt); + + debugfs_create_u32("abyp_opt", 0644, pcfg->dbg_root, + (u32 *)&debug_on_opt); + + debugfs_create_u32("abyp_gpio", 0644, pcfg->dbg_root, + (u32 *)&debug_abyp_gpio_status); + + debugfs_create_u32("trace", 0644, pcfg->dbg_root, + (u32 *)&debug_trace_opt); + + debugfs_create_u32("dual_test", 0644, pcfg->dbg_root, + (u32 *)&pcfg->dual_test); + + debugfs_create_bool("esd_enable", 0644, pcfg->dbg_root, + &(pcfg->lp_ctrl.esd_enable)); + + debugfs_create_u32("esd_cnt", 0644, pcfg->dbg_root, + (u32 *)&(pcfg->lp_ctrl.esd_cnt)); + + if (debugfs_create_file("abyp", 0644, pcfg->dbg_root, display, + &iris_abyp_dbg_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("lp", 0644, pcfg->dbg_root, display, + &iris_lp_dbg_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lp.h b/techpack/display/msm/dsi/iris/dsi_iris5_lp.h new file mode 100755 index 000000000000..f83cc44f7ff7 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lp.h @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_LP_H_ +#define _DSI_IRIS_LP_H_ +#include "dsi_iris5_i3c.h" + +/* option IDs */ +#define ID_SYS_PMU_CTRL 0xf0 +#define ID_SYS_ULPS 0xf1 +#define ID_SYS_MEM_REPAIR 0x07 + +#define ID_SYS_ENTER_ABYP 0x0104 +#define ID_SYS_EXIT_ABYP 0x0105 + +#define ID_RX_ENTER_TTL 0xD0 +#define ID_RX_EXIT_TTL 0xD1 + +/* regs */ +#define REG_ADDR_PMU_CTRL 0xf0000060 +#define REG_ADDR_PMU_STATUS 0xf0000094 +#define IRIS_RUN_STATUS 0xf1240030 +#define IRIS_REG_UPDATE 0xf1250000 +#define DISP_CMD_SHAWDOW_EN_MASK 0x00000040 +#define DISP_CMD_SHAWDOW_EN_SHIFT 6 + +#define IRIS_REG_INTSTAT_RAW 0xf189ffe4 +#define TXFALSE_CONTROL_MASK 0x00040000 +#define PQ_SWITCH_MASK BIT(3) + +enum iris_pmu_domain { + MIPI_PWR = (0x1 << 2), + MIPI2_PWR = (0x1 << 3), + BSRAM_PWR = (0x1 << 4), + FRC_PWR = (0x1 << 5), + PQ_PWR = (0x1 << 6), + DSCU_PWR = (0x1 << 7), + DDSC_PWR = (0x1 << 8), + LCE_PWR = (0x1 << 9), +}; + +enum iris_ulps_sel { + ULPS_NONE = 0x0, + ULPS_MAIN = 0x1, + ULPS_AUX = 0x2, + ULPS_MAIN_AUX = 0x3, +}; + +enum iris_abyp_switch_state { + PASS_THROUGH_STATE = 0, + POWER_UP_STATE, + TTL_CMD_BYPASS_STATE, + ANALOG_BYPASS_ENTER_STATE, + ANALOG_BYPASS_CHECK_STATE, + ANALOG_BYPASS_EXIT_STATE, + CONFIG_MIPI_STATE, + CONFIG_DMA_STATE, + EXIT_TTL_STATE, +}; + +enum iris_abyp_lp_mode { + ABYP_POWER_DOWN_SYS = 1, + ABYP_POWER_DOWN_MIPI = 2, + ABYP_POWER_DOWN_PLL = 3, +}; + +/* parse low power control info */ +int32_t iris_parse_lp_ctrl(struct device_node *np, struct iris_cfg *pcfg); + +/* init iris low power*/ +void iris_lp_preinit(void); +void iris_lp_init(void); + +/* dynamic power gating set */ +void iris_dynamic_power_set(bool enable); + +/* dynamic power gating get */ +bool iris_dynamic_power_get(void); + +/* power on & off mipi2 domain */ +int iris_pmu_mipi2_set(bool on); + +/* power on & off bulksram domain */ +int iris_pmu_bsram_set(bool on); + +/* power on & off frc domain */ +int iris_pmu_frc_set(bool on); + +/* power on & off dsc unit domain */ +int iris_pmu_dscu_set(bool on); + +/* power on & off lce domain */ +int iris_pmu_lce_set(bool on); + +/* lce dynamic pmu mask enable */ +void iris_lce_dynamic_pmu_mask_set(bool enable); + +/* Switch PT and Bypass mode */ +bool iris_abypass_switch_proc(struct dsi_display *display, int mode, bool pending, bool first); + +void iris_lce_power_status_set(bool enable); + +bool iris_lce_power_status_get(void); + +/* trigger DMA to load */ +void iris_dma_trigger_load(void); + +void iris_ulps_source_sel(enum iris_ulps_sel ulps_sel); + +bool iris_ulps_enable_get(void); + +int iris_dbgfs_lp_init(struct dsi_display *display); + +void iris_sde_encoder_rc_lock(void); + +void iris_sde_encoder_rc_unlock(void); + +bool iris_fast_cmd_abyp_exit(void); + +void iris_lp_setting_off(void); + +/* Get Iris lightup opt */ +int iris_lightup_opt_get(void); + +int iris_exit_abyp(bool one_wired); + +void iris_video_abyp_enter(void); + +void iris_video_abyp_exit(void); + +/* get frc domain power state */ +bool iris_pmu_frc_get(void); +/* get bsram domain power state */ +bool iris_pmu_bsram_get(void); +/* Iris abyp lp */ +void iris_abyp_lp(int mode); +/* Iris power up MIPI */ +void iris_power_up_mipi(void); +/* Iris reset MIPI domain*/ +void iris_reset_mipi(void); + +static inline bool iris_disable_ulps(uint8_t path) +{ + bool is_ulps_enable = 0; + + if (path == PATH_I2C) { + is_ulps_enable = iris_ulps_enable_get(); + if (is_ulps_enable) + iris_ulps_source_sel(ULPS_NONE); + iris_i3c_status_set(true); + } + + return is_ulps_enable; +} + +static inline void iris_enable_ulps(uint8_t path, bool is_ulps_enable) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (path == PATH_I2C) { + iris_i3c_status_set(false); + if (is_ulps_enable) { + if (pcfg->pwil_mode == PT_MODE) { + if (iris_pmu_frc_get() == false) { + if (iris_pmu_bsram_get() == false) + iris_ulps_source_sel(ULPS_MAIN); + } + } else if (iris_pmu_frc_get() == false) { + if (pcfg->osd_enable == false) + iris_ulps_source_sel(ULPS_MAIN); + } + } + } +} + +#endif // _DSI_IRIS_LP_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lut.c b/techpack/display/msm/dsi/iris/dsi_iris5_lut.c new file mode 100755 index 000000000000..a3bf87430b3d --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lut.c @@ -0,0 +1,933 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <linux/firmware.h> +#include <linux/debugfs.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_log.h" + +static u8 payload_size; + +static uint32_t lut_lut2[LUT_LEN] = {}; +static uint32_t LUT2_fw[LUT_LEN+LUT_LEN+LUT_LEN] = {}; + +static struct msmfb_iris_ambient_info iris_ambient_lut; +static struct msmfb_iris_maxcll_info iris_maxcll_lut; + +static u8 *iris_ambient_lut_buf; +/* SDR2HDR_UVYGAIN_BLOCK_CNT > SDR2HDR_LUT2_BLOCK_CNT */ +static struct dsi_cmd_desc *dynamic_lut_send_cmd; + +static uint32_t lut_luty[LUT_LEN] = {}; +static uint32_t lut_lutuv[LUT_LEN] = {}; +static uint32_t LUTUVY_fw[LUT_LEN+LUT_LEN+LUT_LEN+LUT_LEN+LUT_LEN+LUT_LEN] = {}; + +static u8 *iris_maxcll_lut_buf; +static struct dsi_cmd_desc *dynamic_lutuvy_send_cmd; + +struct lut_node { + u32 lut_cmd_cnts_max; + u32 hdr_lut2_pkt_cnt; + u32 hdr_lutuvy_pkt_cnt; +}; + +static struct lut_node iris_lut_param; +static u8 firmware_loaded = FIRMWARE_LOAD_FAIL; +static u16 firmware_calibrate_status; + +static u8 cm_lut_opt_cnt = 21; +static u8 gamma_lut_opt_cnt = 8; + +u8 iris_get_fw_status(void) +{ + return firmware_loaded; +} + +void iris_update_fw_status(u8 value) +{ + firmware_loaded = value; +} + +struct msmfb_iris_ambient_info *iris_get_ambient_lut(void) +{ + return &iris_ambient_lut; +} + +struct msmfb_iris_maxcll_info *iris_get_maxcll_info(void) +{ + return &iris_maxcll_lut; +} + +static void _iris_init_ambient_lut(void) +{ + iris_ambient_lut.ambient_lux = 0; + iris_ambient_lut.ambient_bl_ratio = 0; + iris_ambient_lut.lut_lut2_payload = &lut_lut2; + + if (iris_ambient_lut_buf != NULL) { + vfree(iris_ambient_lut_buf); + iris_ambient_lut_buf = NULL; + } + + dynamic_lut_send_cmd = NULL; +} + +static void _iris_init_maxcll_lut(void) +{ + iris_maxcll_lut.mMAXCLL = 2200; + iris_maxcll_lut.lut_luty_payload = &lut_luty; + iris_maxcll_lut.lut_lutuv_payload = &lut_lutuv; + + if (iris_maxcll_lut_buf != NULL) { + vfree(iris_maxcll_lut_buf); + iris_maxcll_lut_buf = NULL; + } + + dynamic_lutuvy_send_cmd = NULL; +} + +static void _iris_init_lut_buf(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + payload_size = pcfg->split_pkt_size; + memset(&iris_lut_param, 0x00, sizeof(iris_lut_param)); + + /* for HDR ambient light */ + _iris_init_ambient_lut(); + + /* for HDR maxcll */ + _iris_init_maxcll_lut(); +} + +static int32_t _iris_request_firmware(const struct firmware **fw, + const uint8_t *name) +{ + int32_t rc = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct device *dev = &pcfg->display->pdev->dev; + + if (name == NULL) { + IRIS_LOGE("%s(), firmware is null", __func__); + return -EINVAL; + } + + rc = request_firmware(fw, name, dev); + if (rc) { + IRIS_LOGE("%s(), failed to request firmware: %s, return: %d", + __func__, name, rc); + return rc; + } + + IRIS_LOGE("%s(), request firmware [Success], name: %s, size: %zu bytes", + __func__, name, (*fw)->size); + + return rc; +} + +static void _iris_release_firmware(const struct firmware **fw) +{ + if (*fw) { + release_firmware(*fw); + *fw = NULL; + } +} + +static int _iris_change_lut_type_addr( + struct iris_ip_opt *dest, struct iris_ip_opt *src) +{ + int rc = -EINVAL; + struct dsi_cmd_desc *desc = NULL; + + if (!src || !dest) { + IRIS_LOGE("%s(), src or dest is null", __func__); + return rc; + } + + desc = src->cmd; + if (!desc) { + IRIS_LOGE("%s(), invalid desc.", __func__); + return rc; + } + + IRIS_LOGD("%s(), desc len: %zu", __func__, desc->msg.tx_len); + iris_change_type_addr(dest, src); + + return 0; +} + +static int _iris_change_dbc_type_addr(void) +{ + int i = 0; + int rc = -EINVAL; + u8 ip = IRIS_IP_DBC; + u8 opt_id = 0xFE; + u8 lut_opt_id = CABC_DLV_OFF; + struct iris_ip_opt *lut_popt = NULL; + struct iris_ip_opt *popt = NULL; + + /*DBC change*/ + IRIS_LOGD("%s(%d)", __func__, __LINE__); + popt = iris_find_ip_opt(ip, opt_id); + if (!popt) + return rc; + + for (i = 0; i < DBC_HIGH; i++) { + lut_popt = iris_find_ip_opt(DBC_LUT, lut_opt_id + i); + if (!lut_popt) + return rc; + + rc = _iris_change_lut_type_addr(lut_popt, popt); + } + return rc; +} + +static int _iris_change_gamma_type_addr(void) +{ + u8 i = 0; + int rc = -EINVAL; + u8 ip = IRIS_IP_DPP; + u8 opt_id = 0xFE; + u8 lut_opt_id = 0; + struct iris_ip_opt *lut_popt = NULL; + struct iris_ip_opt *popt = NULL; + + IRIS_LOGD("%s(%d)", __func__, __LINE__); + popt = iris_find_ip_opt(ip, opt_id); + if (!popt) { + IRIS_LOGE("%s(), cann't find valid option, input ip: %#x, opt: %#x.", + __func__, ip, opt_id); + return rc; + } + + for (i = 0; i < gamma_lut_opt_cnt; i++) { + lut_popt = iris_find_ip_opt(GAMMA_LUT, lut_opt_id + i); + if (!lut_popt) { + IRIS_LOGE("%s(), cann't find valid lut option, input ip: %#x, opt: %#x.", + __func__, GAMMA_LUT, lut_opt_id + i); + return rc; + } + + rc = _iris_change_lut_type_addr(lut_popt, popt); + } + + return rc; +} + + +static int _iris_change_sdr2hdr_type_addr(void) +{ + int i = 0; + int j = 0; + int rc = -EINVAL; + u8 ip = IRIS_IP_SDR2HDR; + u8 opt_id = 0xFE; + u8 lut_opt_id = SDR2HDR_INV_UV0; + struct iris_ip_opt *lut_popt = NULL; + struct iris_ip_opt *popt = NULL; + + IRIS_LOGD("%s(%d)", __func__, __LINE__); + for (j = SDR2HDR_INV_UV0; j <= SDR2HDR_INV_UV1; j++) { + opt_id -= j - SDR2HDR_INV_UV0; + popt = iris_find_ip_opt(ip, opt_id); + if (!popt) { + IRIS_LOGE("%s(), cann't find valid option, input ip: %#x, opt: %#x.", + __func__, ip, opt_id); + return rc; + } + + for (i = 0; i < SDR2HDR_LEVEL_CNT; i++) { + lut_opt_id = j << 4 | i; + lut_popt = iris_find_ip_opt(SDR2HDR_LUT, lut_opt_id); + if (!lut_popt) { + IRIS_LOGE("%s(), cann't find valid lut option, input ip: %#x, opt: %#x.", + __func__, SDR2HDR_LUT, lut_opt_id); + return rc; + } + + rc = _iris_change_lut_type_addr(lut_popt, popt); + } + } + return rc; +} + +static int _iris_change_dither_type_addr(void) +{ + int rc = -EINVAL; + u8 ip = IRIS_IP_DPP; + u8 opt_id = 0xF8; + u8 lut_opt_id = 0; + struct iris_ip_opt *lut_popt = NULL; + struct iris_ip_opt *popt = NULL; + + IRIS_LOGD("%s(%d)", __func__, __LINE__); + popt = iris_find_ip_opt(ip, opt_id); + if (!popt) { + IRIS_LOGE("%s(), cann't find valid option, input ip: %#x, opt: %#x.", + __func__, ip, opt_id); + return rc; + } + + lut_popt = iris_find_ip_opt(DPP_DITHER_LUT, lut_opt_id); + if (!lut_popt) { + IRIS_LOGE("%s(), cann't find valid lut option, input ip: %#x, opt: %#x.", + __func__, DPP_DITHER_LUT, lut_opt_id); + return rc; + } + + rc = _iris_change_lut_type_addr(lut_popt, popt); + + return rc; +} + +static int _iris_send_lut_for_dma(void) +{ + int rc = 0; + + /*register level*/ + rc = _iris_change_dbc_type_addr(); + rc = _iris_change_gamma_type_addr(); + rc = _iris_change_sdr2hdr_type_addr(); + rc = _iris_change_dither_type_addr(); + + return rc; +} + +static void _iris_parse_panel_nits(const struct firmware *fw) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->panel_nits = fw->data[fw->size-2]<<8 | fw->data[fw->size-3]; + IRIS_LOGI("%s(), panel nits: 0x%04x.", __func__, pcfg->panel_nits); +} + +static u8 _iris_parse_calibrate_status(const struct firmware *fw) +{ + u8 calibrate_status = 0; + + calibrate_status = fw->data[fw->size-1]; + IRIS_LOGI("%s(), panel calibrate status: 0x%02x.", + __func__, calibrate_status); + + return calibrate_status; +} + +int iris_parse_lut_cmds(u8 flag) +{ + int ret = 0; + struct iris_data data[3] = {{NULL, 0}, {NULL, 0}, {NULL, 0} }; + const struct firmware *fw = NULL; + const struct firmware *ccf1_fw = NULL; + const struct firmware *ccf2_fw = NULL; + struct iris_ip_index *pip_index = NULL; + struct iris_cfg *pcfg = NULL; + u8 firmware_state = 0; + char ccf1_name[256] = {}; + char ccf2_name[256] = {}; + + firmware_calibrate_status = 0; + pip_index = iris_get_ip_idx(IRIS_LUT_PIP_IDX); + _iris_init_lut_buf(); + + // Load "iris5.fw". + ret = _iris_request_firmware(&fw, IRIS_FIRMWARE_NAME); + if (!ret) { + firmware_state |= (1<<0); + data[0].buf = fw->data; + data[0].size = fw->size; + IRIS_LOGI("%s(%d), request name: %s, size: %u.", + __func__, __LINE__, IRIS_FIRMWARE_NAME, data[0].size); + } else { + IRIS_LOGE("%s(), failed to request: %s", __func__, IRIS_FIRMWARE_NAME); + } + + // Load "iris5_ccf1.fw". + if (flag == 0 || flag == 2) { + // Load calibrated firmware. + strlcpy(ccf1_name, IRIS_CCF1_CALIBRATED_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf1_fw, ccf1_name); + if (ret && flag == 0) { + // Load golden firmware. + strlcpy(ccf1_name, IRIS_CCF1_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf1_fw, ccf1_name); + } + } else { + // Load golden firmware. + strlcpy(ccf1_name, IRIS_CCF1_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf1_fw, ccf1_name); + } + if (!ret) { + const uint32_t ccf1_per_pkg_size = 23584; + const uint32_t ccf1_tail_size = 3; + + if ((ccf1_fw->size - ccf1_tail_size) % ccf1_per_pkg_size == 0 + && ccf1_fw->size > ccf1_per_pkg_size) { + u8 fw_calibrate_st = 0; + + firmware_state |= (1<<1); + data[1].buf = ccf1_fw->data; + + // ommit the last 3 bytes for parsing firmware + // panel nits(2 bytes) and panel calibration status(1 byte) + data[1].size = ccf1_fw->size - 3; + _iris_parse_panel_nits(ccf1_fw); + fw_calibrate_st = _iris_parse_calibrate_status(ccf1_fw); + firmware_calibrate_status |= fw_calibrate_st; + + cm_lut_opt_cnt = (ccf1_fw->size - ccf1_tail_size) / ccf1_per_pkg_size; + IRIS_LOGI("%s(%d), request name: %s, size: %u, option count: %u.", + __func__, __LINE__, + ccf1_name, data[1].size, cm_lut_opt_cnt); + } else { + IRIS_LOGE("%s(), invalid format for firmware: %s", + __func__, ccf1_name); + } + } else { + IRIS_LOGE("%s(), failed to request: %s", __func__, ccf1_name); + } + + // Load "iris5_ccf2.fw". + if (flag == 0 || flag == 2) { + // Load calibrated firmware. + strlcpy(ccf2_name, IRIS_CCF2_CALIBRATED_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf2_fw, ccf2_name); + if (ret && flag == 0) { + // Load golden firmware. + strlcpy(ccf2_name, IRIS_CCF2_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf2_fw, ccf2_name); + } + } else { + // Load golden firmware. + strlcpy(ccf2_name, IRIS_CCF2_FIRMWARE_NAME, 256); + ret = _iris_request_firmware(&ccf2_fw, ccf2_name); + } + if (!ret) { + const uint32_t ccf2_per_pkg_size = 428; + const uint32_t ccf2_tail_size = 1; + + if ((ccf2_fw->size - ccf2_tail_size) % ccf2_per_pkg_size == 0 + && ccf2_fw->size > ccf2_per_pkg_size) { + u8 fw_calibrate_st = 0; + + firmware_state |= (1<<2); + data[2].buf = ccf2_fw->data; + + // ommit the last 1 byte for parsing firmware + // it's panel calibration status + data[2].size = ccf2_fw->size - 1; + fw_calibrate_st = _iris_parse_calibrate_status(ccf2_fw); + firmware_calibrate_status |= fw_calibrate_st<<8; + + gamma_lut_opt_cnt = (ccf2_fw->size - ccf2_tail_size) / ccf2_per_pkg_size; + IRIS_LOGI("%s(%d), request name: %s, size: %u, option count: %u.", + __func__, __LINE__, ccf2_name, data[2].size, gamma_lut_opt_cnt); + } else { + IRIS_LOGE("%s(), invalid format for firmware: %s", + __func__, ccf2_name); + } + } else { + IRIS_LOGE("%s(), failed to request: %s", __func__, ccf2_name); + } + + firmware_loaded = (firmware_state == 0x07 ? FIRMWARE_LOAD_SUCCESS : FIRMWARE_LOAD_FAIL); + IRIS_LOGI("%s(), load firmware: %s, state: %#x", + __func__, + firmware_loaded == FIRMWARE_LOAD_SUCCESS ? "success" : "fail", + firmware_state); + if (firmware_state != 0) { + pcfg = iris_get_cfg(); + ret = iris_attach_cmd_to_ipidx(data, (sizeof(data))/(sizeof(data[0])), + pip_index); + if (ret) + IRIS_LOGE("%s(), failed to load iris fw", __func__); + + _iris_send_lut_for_dma(); + } + + _iris_release_firmware(&fw); + _iris_release_firmware(&ccf1_fw); + _iris_release_firmware(&ccf2_fw); + + return ret; +} + +/*add lut cmds to bufs for sending*/ +static void _iris_prepare_lut_cmds(struct iris_ip_opt *popt) +{ + int pos = 0; + struct iris_cfg *pcfg = NULL; + struct dsi_cmd_desc *pdesc = NULL; + + pcfg = iris_get_cfg(); + + pdesc = pcfg->iris_cmds.iris_cmds_buf; + pos = pcfg->iris_cmds.cmds_index; + + IRIS_LOGD("%s(), %p %p len: %d", + __func__, &pdesc[pos], popt, popt->cmd_cnt); + memcpy(&pdesc[pos], popt->cmd, sizeof(*pdesc) * popt->cmd_cnt); + pos += popt->cmd_cnt; + pcfg->iris_cmds.cmds_index = pos; +} + +static void _iris_fomat_lut_cmds(u8 lut_type, u8 opt_id) +{ + struct iris_ip_opt *popt = NULL; + + popt = iris_find_ip_opt(lut_type, opt_id); + if (!popt) { + IRIS_LOGW("%s(%d), invalid opt id: %#x.", + __func__, __LINE__, opt_id); + return; + } + _iris_prepare_lut_cmds(popt); +} + +int iris_send_lut(u8 lut_type, u8 lut_table_index, u32 lut_abtable_index) +{ + int i = 0; + u8 lut_opt_id = 0xfe; + int len = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + struct dsi_cmd_desc *pdesc = pcfg->iris_cmds.iris_cmds_buf; + + switch (lut_type) { + case DBC_LUT: + if (!((lut_table_index <= DBC_HIGH /*&& lut_table_index >= DBC_INIT*/) || + (lut_table_index <= CABC_DLV_HIGH && lut_table_index >= CABC_DLV_OFF))) + break; + + /*lut_abtable_index will be used at AB_table index here.*/ + if (lut_abtable_index > 0) + lut_abtable_index = 1; + + len = 1; + if (lut_table_index < CABC_DLV_OFF) { + /*find lut table ip and opt id*/ + lut_opt_id = (lut_table_index & 0x3f) | (lut_abtable_index << 7); + /*even and odd*/ + if (lut_table_index != DBC_INIT) + len = 2; + } else + lut_opt_id = lut_table_index; + + for (i = 0; i < len; i++) { + /*dbc level as to a table for example:odd 0x1 and even 0x41*/ + lut_opt_id = (i << 6 | lut_opt_id); + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + } + IRIS_LOGI("%s(): call DBC_LUT, index: %#x.", __func__, lut_table_index); + break; + + case CM_LUT: + if (lut_table_index >= cm_lut_opt_cnt) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(): call CM_LUT, index: %#x.", __func__, lut_table_index); + break; + + case SDR2HDR_LUT: + if (lut_table_index > (SDR2HDR_LEVEL5 | (SDR2HDR_INV_UV1<<4))) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call SDR2HDR_LUT, index: %#x.", __func__, lut_table_index); + break; + + case SCALER1D_LUT: + case SCALER1D_PP_LUT: + if (lut_table_index >= SCALER1D_LUT_NUMBER) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call SCALER1D, ip: %#x, index: %d.", __func__, + lut_type, lut_table_index); + break; + + case AMBINET_HDR_GAIN: + if (!iris_maxcll_lut_buf || !dynamic_lutuvy_send_cmd) + break; + + memcpy(&pdesc[pcfg->iris_cmds.cmds_index], &dynamic_lutuvy_send_cmd[0], + sizeof(struct dsi_cmd_desc)*iris_lut_param.hdr_lutuvy_pkt_cnt); + + pcfg->iris_cmds.cmds_index += iris_lut_param.hdr_lutuvy_pkt_cnt; + IRIS_LOGI("%s(), ambinet hdr gain.", __func__); + break; + + case AMBINET_SDR2HDR_LUT: + if (!iris_ambient_lut_buf || !dynamic_lut_send_cmd) + break; + + memcpy(&pdesc[pcfg->iris_cmds.cmds_index], + &dynamic_lut_send_cmd[0], + sizeof(struct dsi_cmd_desc) + * iris_lut_param.hdr_lut2_pkt_cnt); + + pcfg->iris_cmds.cmds_index += + iris_lut_param.hdr_lut2_pkt_cnt; + break; + + case GAMMA_LUT: + if (lut_table_index >= gamma_lut_opt_cnt) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call GAMMA_LUT, index: %d.", __func__, lut_table_index); + break; + + case FRC_PHASE_LUT: + if (lut_table_index >= FRC_PHASE_TYPE_CNT) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call FRC_PHASE_LUT, index: %d.", __func__, lut_table_index); + break; + + case APP_CODE_LUT: + if (lut_table_index != 0) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call APP_CODE_LUT, index: %d.", __func__, lut_table_index); + break; + + case DPP_DITHER_LUT: + if (lut_table_index != 0) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call DPP_DITHER_LUT, index: %d.", __func__, lut_table_index); + break; + + case DTG_PHASE_LUT: + if (lut_table_index != 0) { + IRIS_LOGW("%s(%d), invalid table index %d of type: %#x.", + __func__, __LINE__, lut_table_index, lut_type); + break; + } + + lut_opt_id = lut_table_index & 0xff; + _iris_fomat_lut_cmds(lut_type, lut_opt_id); + IRIS_LOGI("%s(), call DTG_PHASE_LUT, index: %d.", __func__, lut_table_index); + break; + + default: + IRIS_LOGW("%s(), type of %d have no cmd.", __func__, lut_type); + break; + } + + IRIS_LOGD("%s(), lut type: %#x, lut index: %#x, ab index: %#x, cmd count: %d, max count: %d", + __func__, + lut_type, lut_table_index, lut_abtable_index, + pcfg->iris_cmds.cmds_index, iris_lut_param.lut_cmd_cnts_max); + + return IRIS_SUCCESS; +} + +void iris_update_ambient_lut(enum LUT_TYPE lutType, u32 lutpos) +{ + u32 len = 0; + u32 hdr_payload_size = payload_size; + u32 hdr_pkt_size = hdr_payload_size + DIRECT_BUS_HEADER_SIZE; + u32 hdr_block_pkt_cnt = + (SDR2HDR_LUT_BLOCK_SIZE/2 + hdr_payload_size - 1) + / hdr_payload_size; + u32 iris_lut_buf_index, lut_block_index, lut_block_cnt; + u32 lut_pkt_cmd_index; + u32 temp_index, index_i; + u32 dbus_addr_start; + u32 lut_fw_index; + u32 cmd_payload_len; + struct ocp_header ocp_dbus_header; + + memset(&ocp_dbus_header, 0, sizeof(ocp_dbus_header)); + ocp_dbus_header.header = 0x0004000C; + ocp_dbus_header.address = SDR2HDR_LUT2_ADDRESS; + + if (lutpos == 0xFFE00000) + hdr_block_pkt_cnt = + (SDR2HDR_LUT_BLOCK_SIZE + hdr_payload_size - 1) + / hdr_payload_size; + + if (lutType != AMBINET_SDR2HDR_LUT) { + IRIS_LOGE("%s input lutType error %d", __func__, lutType); + return; + } + + if (lutpos == 0xFFE00000) + dbus_addr_start = SDR2HDR_LUT2_ADDRESS; + else + dbus_addr_start = SDR2HDR_LUT2_ADDRESS + lutpos * SDR2HDR_LUT_BLOCK_SIZE / 2; + lut_block_cnt = SDR2HDR_LUT2_BLOCK_CNT; + + // copy lut2 to the firmware format. + // lut2 is EVEN+ODD, + // LUT2_fw is EVEN ODD EVEN ODD EVEN ODD + for (index_i = 0; index_i < LUT_LEN; index_i++) { + if (lutpos == 0xFFE00000) { + lut_fw_index = index_i / 2; + if (index_i % 2 != 0) // ODD + lut_fw_index += LUT_LEN / 2; + LUT2_fw[lut_fw_index] = lut_lut2[index_i]; + LUT2_fw[lut_fw_index + LUT_LEN] = lut_lut2[index_i]; + LUT2_fw[lut_fw_index + LUT_LEN + LUT_LEN] = lut_lut2[index_i]; + } else { + if (index_i % 2 == 0) { + lut_fw_index = index_i / 4; + if (index_i % 4 != 0) /* ODD */ + lut_fw_index += LUT_LEN / 4; + LUT2_fw[lut_fw_index] = lut_lut2[index_i]; + LUT2_fw[lut_fw_index + LUT_LEN / 2] = lut_lut2[index_i]; + LUT2_fw[lut_fw_index + LUT_LEN / 2 + LUT_LEN / 2] = + lut_lut2[index_i]; + } + } + } + + if (dynamic_lut_send_cmd == NULL) { + len = sizeof(struct dsi_cmd_desc) + * hdr_pkt_size * hdr_block_pkt_cnt + * SDR2HDR_LUT2_BLOCK_NUMBER; + dynamic_lut_send_cmd = vzalloc(len); + if (dynamic_lut_send_cmd == NULL) { + IRIS_LOGE("%s(), failed to alloc mem", __func__); + return; + } + iris_lut_param.lut_cmd_cnts_max += + hdr_block_pkt_cnt * SDR2HDR_LUT2_BLOCK_NUMBER; + iris_lut_param.hdr_lut2_pkt_cnt = + hdr_block_pkt_cnt * SDR2HDR_LUT2_BLOCK_NUMBER; + } + + if (iris_ambient_lut_buf) + memset(iris_ambient_lut_buf, 0, + hdr_pkt_size * iris_lut_param.hdr_lut2_pkt_cnt); + + if (!iris_ambient_lut_buf) { + len = hdr_pkt_size * iris_lut_param.hdr_lut2_pkt_cnt; + iris_ambient_lut_buf = vzalloc(len); + } + if (!iris_ambient_lut_buf) + return; + + lut_fw_index = 0; + /*parse LUT2*/ + for (lut_block_index = 0; + lut_block_index < lut_block_cnt; + lut_block_index++){ + + ocp_dbus_header.address = dbus_addr_start + + lut_block_index + * SDR2HDR_LUT_BLOCK_ADDRESS_INC; + + for (lut_pkt_cmd_index = 0; + lut_pkt_cmd_index < hdr_block_pkt_cnt; + lut_pkt_cmd_index++) { + + iris_lut_buf_index = + lut_block_index * hdr_pkt_size + * hdr_block_pkt_cnt + + lut_pkt_cmd_index * hdr_pkt_size; + + if (lut_pkt_cmd_index == hdr_block_pkt_cnt-1) { + if (lutpos == 0xFFE00000) + cmd_payload_len = SDR2HDR_LUT_BLOCK_SIZE + - (hdr_block_pkt_cnt-1) * hdr_payload_size; + else + cmd_payload_len = SDR2HDR_LUT_BLOCK_SIZE/2 + - (hdr_block_pkt_cnt-1) * hdr_payload_size; + } else + cmd_payload_len = hdr_payload_size; + + temp_index = lut_pkt_cmd_index + + hdr_block_pkt_cnt * lut_block_index; + dynamic_lut_send_cmd[temp_index].msg.type = 0x29; + dynamic_lut_send_cmd[temp_index].msg.tx_len = + cmd_payload_len + DIRECT_BUS_HEADER_SIZE; + dynamic_lut_send_cmd[temp_index].post_wait_ms = 0; + dynamic_lut_send_cmd[temp_index].msg.tx_buf = + iris_ambient_lut_buf + iris_lut_buf_index; + + memcpy(&iris_ambient_lut_buf[iris_lut_buf_index], + &ocp_dbus_header, DIRECT_BUS_HEADER_SIZE); + iris_lut_buf_index += DIRECT_BUS_HEADER_SIZE; + + memcpy(&iris_ambient_lut_buf[iris_lut_buf_index], + &LUT2_fw[lut_fw_index], cmd_payload_len); + + lut_fw_index += cmd_payload_len / 4; + ocp_dbus_header.address += cmd_payload_len; + } + } +} + +void iris_update_maxcll_lut(enum LUT_TYPE lutType, u32 lutpos) +{ + u32 hdr_payload_size = payload_size; + u32 hdr_pkt_size = hdr_payload_size + DIRECT_BUS_HEADER_SIZE; + u32 hdr_block_pkt_cnt = (SDR2HDR_LUT_BLOCK_SIZE / 2 + hdr_payload_size - 1) / hdr_payload_size; + u32 iris_lut_buf_index, lut_block_index, lut_block_cnt, lut_pkt_cmd_index; + u32 temp_index, index_i; + u32 dbus_addr_start; + u32 lut_fw_index; + u32 cmd_payload_len; + struct ocp_header ocp_dbus_header; + + memset(&ocp_dbus_header, 0, sizeof(ocp_dbus_header)); + ocp_dbus_header.header = 0x0004000C; + ocp_dbus_header.address = SDR2HDR_LUTUVY_ADDRESS; + + if (lutpos == 0xFFFF0000) + hdr_block_pkt_cnt = (SDR2HDR_LUT_BLOCK_SIZE + hdr_payload_size - 1) / hdr_payload_size; + + if (lutType != AMBINET_HDR_GAIN) { + IRIS_LOGE("%s input lutType error %d", __func__, lutType); + return; + } + + dbus_addr_start = SDR2HDR_LUTUVY_ADDRESS; + lut_block_cnt = SDR2HDR_LUTUVY_BLOCK_CNT; + + // copy lutuvy to the firmware format. + // lutuvy is EVEN+ODD, LUT2_fw is EVEN ODD EVEN ODD EVEN ODD + for (index_i = 0; index_i < LUT_LEN; index_i++) { + if (lutpos == 0xFFFF0000) { + lut_fw_index = index_i / 2; + if (index_i % 2 == 0) // ODD + lut_fw_index += LUT_LEN / 2; + LUTUVY_fw[lut_fw_index] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + LUT_LEN] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + 2 * LUT_LEN] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + 3 * LUT_LEN] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + 4 * LUT_LEN] = lut_luty[index_i]; + LUTUVY_fw[lut_fw_index + 5 * LUT_LEN] = lut_luty[index_i]; + } else { + if (index_i % 2 == 0) { + lut_fw_index = index_i / 4; + if (index_i % 4 != 0) // ODD + lut_fw_index += LUT_LEN / 4; + LUTUVY_fw[lut_fw_index] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + LUT_LEN / 2] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + LUT_LEN] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + 3 * LUT_LEN / 2] = lut_lutuv[index_i]; + LUTUVY_fw[lut_fw_index + 2 * LUT_LEN] = lut_luty[index_i]; + LUTUVY_fw[lut_fw_index + 5 * LUT_LEN / 2] = lut_luty[index_i]; + } + } + } + + if (dynamic_lutuvy_send_cmd == NULL) { + dynamic_lutuvy_send_cmd = vzalloc(sizeof(struct dsi_cmd_desc) * hdr_pkt_size * hdr_block_pkt_cnt * SDR2HDR_LUTUVY_BLOCK_NUMBER); + if (dynamic_lutuvy_send_cmd == NULL) { + IRIS_LOGE("%s: failed to alloc mem", __func__); + return; + } + iris_lut_param.lut_cmd_cnts_max += hdr_block_pkt_cnt * SDR2HDR_LUTUVY_BLOCK_NUMBER; + iris_lut_param.hdr_lutuvy_pkt_cnt = hdr_block_pkt_cnt * SDR2HDR_LUTUVY_BLOCK_NUMBER; + } + + if (iris_maxcll_lut_buf) + memset(iris_maxcll_lut_buf, 0, hdr_pkt_size * iris_lut_param.hdr_lutuvy_pkt_cnt); + + if (!iris_maxcll_lut_buf) + iris_maxcll_lut_buf = vzalloc(hdr_pkt_size * iris_lut_param.hdr_lutuvy_pkt_cnt); + + if (!iris_maxcll_lut_buf) { + IRIS_LOGE("%s: failed to alloc mem", __func__); + return; + } + + lut_fw_index = 0; + //parse LUTUVY + for (lut_block_index = 0; lut_block_index < lut_block_cnt; lut_block_index++) { + ocp_dbus_header.address = dbus_addr_start + lut_block_index*SDR2HDR_LUT_BLOCK_ADDRESS_INC; + if (lutpos != 0xFFFF0000) + ocp_dbus_header.address += lutpos * SDR2HDR_LUT_BLOCK_SIZE/2; + for (lut_pkt_cmd_index = 0; lut_pkt_cmd_index < hdr_block_pkt_cnt; lut_pkt_cmd_index++) { + iris_lut_buf_index = lut_block_index*hdr_pkt_size*hdr_block_pkt_cnt + lut_pkt_cmd_index*hdr_pkt_size; + if (lut_pkt_cmd_index == hdr_block_pkt_cnt-1) { + cmd_payload_len = SDR2HDR_LUT_BLOCK_SIZE/2 - (hdr_block_pkt_cnt-1) * hdr_payload_size; + if (lutpos == 0xFFFF0000) + cmd_payload_len += SDR2HDR_LUT_BLOCK_SIZE/2; + } else + cmd_payload_len = hdr_payload_size; + + temp_index = lut_pkt_cmd_index + hdr_block_pkt_cnt * lut_block_index; + dynamic_lutuvy_send_cmd[temp_index].msg.type = 0x29; + dynamic_lutuvy_send_cmd[temp_index].msg.tx_len = cmd_payload_len + DIRECT_BUS_HEADER_SIZE; + dynamic_lutuvy_send_cmd[temp_index].post_wait_ms = 0; + dynamic_lutuvy_send_cmd[temp_index].msg.tx_buf = iris_maxcll_lut_buf + iris_lut_buf_index; + + memcpy(&iris_maxcll_lut_buf[iris_lut_buf_index], &ocp_dbus_header, DIRECT_BUS_HEADER_SIZE); + iris_lut_buf_index += DIRECT_BUS_HEADER_SIZE; + + memcpy(&iris_maxcll_lut_buf[iris_lut_buf_index], &LUTUVY_fw[lut_fw_index], cmd_payload_len); + lut_fw_index += cmd_payload_len/4; + ocp_dbus_header.address += cmd_payload_len; + } + } +} + +void iris_update_gamma(void) +{ + if (iris_get_fw_status() != FIRMWARE_LOAD_SUCCESS) + return; + + iris_scaler_gamma_enable(true, 1); + iris_update_fw_status(FIRMWARE_IN_USING); +} + +int iris_dbgfs_fw_calibrate_status_init(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + debugfs_create_u16("fw_calibrate_status", 0644, pcfg->dbg_root, + &firmware_calibrate_status); + + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_lut.h b/techpack/display/msm/dsi/iris/dsi_iris5_lut.h new file mode 100755 index 000000000000..969043c69509 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_lut.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_LUT_H_ +#define _DSI_IRIS_LUT_H_ + +int iris_parse_lut_cmds(u8 flag); +int iris_send_lut(u8 lut_type, u8 lut_table_index, u32 lut_abtable_index); +void iris_update_ambient_lut(enum LUT_TYPE lutType, u32 lutPos); +void iris_update_maxcll_lut(enum LUT_TYPE lutType, u32 lutpos); +u8 iris_get_fw_status(void); +void iris_update_fw_status(u8 value); +void iris_update_gamma(void); +int iris_dbgfs_fw_calibrate_status_init(void); + +#endif // _DSI_IRIS_LUT_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.c b/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.c new file mode 100755 index 000000000000..e4e484a9e6e2 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.c @@ -0,0 +1,1660 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +#include <linux/gcd.h> + +#include <video/mipi_display.h> +#include <drm/drm_mipi_dsi.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_frc.h" +#include "dsi_iris5_log.h" + +struct iris_frc_setting *frc_setting; +struct iris_mspwil_parameter mspwil_par; +static int iris_frc_label = 0; +static int iris_frc_var_disp = 0; //0: disable, 1: set before FRC, 2: set after FRC +// bit[4], enable sw configure, bit[3:0], sw motion level, 0-4 +static int iris_frc_mnt_level = 0; +static int iris_frc_dynamic_off = 1; +static int iris_frc_pt_switch_on = 1; +//mcu is enabled in prelightup stage, and iris_mcu_enable is no need to enabled. +static int iris_mcu_enable = 1; // 0: disable, 1: dynamic enable , 2: always enable +static int iris_mcu_stop_check = 1; +int iris_w_path_select = 1; //0: i2c, 1: dsi +int iris_r_path_select = 1; //0: i2c, 1: dsi +int iris_frc_dma_disable = 0; +#define IRIS_FRC_CMD_PAYLOAD_LENGTH 300 // 128 registers +static u32 *iris_frc_cmd_payload; +static int iris_frc_cmd_payload_count; +static int iris_frc_demo_window; +static int iris_dport_output_toggle = 1; +static int iris_frc_fallback_disable = 0; +static int iris_dynamic_sadgain_mid = 8; +static int iris_dynamic_sadgain_low = 16; +static int iris_dynamic_sadcore_mid = 10; +static int iris_dynamic_sadcore_low = 4; +static int iris_dynamic_outgain_mid = 8; +static int iris_dynamic_outgain_low = 16; +static int iris_dynamic_outcore_mid = 10; +static int iris_dynamic_outcore_low = 6; +static int iris_frc_osd_protection = 0; +static int iris_mvc_tuning = 1; +static int iris_mtnsw_low_th = 8; +static int iris_mtnsw_high_th = 3; +static int iris_frcpt_switch_th = 0x3564; +static int iris_te_dly_frc = -1; +static int iris_display_vtotal = -1; +static u32 iris_val_frcc_reg8; +static int iris_frc_var_disp_dbg = 0; +static int iris_frc_var_disp_dual = 2; +static int iris_frc_pt_switch_on_dbg = 1; + +static void iris_frc_cmd_payload_init(void) +{ + iris_frc_cmd_payload_count = 0; + if (iris_frc_cmd_payload == NULL) + iris_frc_cmd_payload = vmalloc(IRIS_FRC_CMD_PAYLOAD_LENGTH*sizeof(u32)); + if (iris_frc_cmd_payload == NULL) + IRIS_LOGE("can not vmalloc size = %d in %s", IRIS_FRC_CMD_PAYLOAD_LENGTH, __func__); +} + +static void iris_frc_cmd_payload_release(void) +{ + if (iris_frc_cmd_payload != NULL && iris_frc_cmd_payload_count != 0) { + IRIS_LOGI("iris_frc_cmd_payload_count: %d", iris_frc_cmd_payload_count); + iris_ocp_write_mult_vals(iris_frc_cmd_payload_count, iris_frc_cmd_payload); + vfree(iris_frc_cmd_payload); + iris_frc_cmd_payload = NULL; + } +} + +void iris_frc_reg_add(u32 addr, u32 val, bool last) +{ + u32 *payload = &iris_frc_cmd_payload[iris_frc_cmd_payload_count]; + + if (iris_frc_cmd_payload_count < IRIS_FRC_CMD_PAYLOAD_LENGTH) { + *payload = addr; + payload++; + *payload = val; + iris_frc_cmd_payload_count += 2; + } else { + IRIS_LOGE("payload buffer lenght is not enough! %s", __func__); + } +} + +void iris_rfb_mode_enter(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->rx_mode == pcfg->tx_mode) + pcfg->pwil_mode = PT_MODE; + else + pcfg->pwil_mode = RFB_MODE; + IRIS_LOGI("rx_mode: %d, tx_mode: %d", pcfg->rx_mode, pcfg->tx_mode); + if (pcfg->osd_enable) + iris_psf_mif_efifo_set(pcfg->pwil_mode, pcfg->osd_enable); + iris_set_pwil_mode(pcfg->panel, pcfg->pwil_mode, pcfg->osd_enable, DSI_CMD_SET_STATE_HS); +} + +void iris_frc_mode_enter(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->pwil_mode = FRC_MODE; + iris_set_pwil_mode(pcfg->panel, pcfg->pwil_mode, pcfg->osd_enable, DSI_CMD_SET_STATE_HS); +} + +u32 iris_frc_video_hstride_calc(u16 hres, u16 bpp, u16 slice_num) +{ + u32 hstride; + + hstride = bpp * ((hres + slice_num - 1) / slice_num); + hstride = (hstride + 15) >> 4; + hstride = ((hstride + 7) / 8) * 8; + hstride = (hstride + 63) / 64; + + return hstride; +} + +static bool iris_frc_setting_check(void) +{ +#define IRIS_FRC_V2_LUT_TABLE_NUM 19 + struct frc_lut_config { + int index; + int in_out_ratio; + int period_phasenum; + int idx_max; + }; + //int v2_table[IRIS_FRC_LUT_TABLE_NUM]; + int inout_ratio = frc_setting->in_fps | frc_setting->out_fps<<8; + int i; + struct iris_cfg *pcfg = iris_get_cfg(); + //int ppn_table[IRIS_FRC_LUT_TABLE_NUM]; // period, phasenum + //int idx_max_table[IRIS_FRC_LUT_TABLE_NUM]; //phaselut index max + struct frc_lut_config config_table[IRIS_FRC_V2_LUT_TABLE_NUM+8] = { + { 1, 12 | 60 << 8, 1 | 5 << 11, 0}, + { 2, 12 | 90 << 8, 2 | 15 << 11, 1}, + { 3, 12 | 120 << 8, 1 | 10 << 11, 0}, + { 4, 15 | 60 << 8, 1 | 4 << 11, 1}, + { 5, 15 | 90 << 8, 1 | 6 << 11, 0}, + { 6, 15 | 120 << 8, 1 | 8 << 11, 0}, + { 7, 24 | 60 << 8, 2 | 5 << 11, 1}, + { 8, 24 | 90 << 8, 4 | 15 << 11, 2}, + { 9, 24 | 120 << 8, 2 | 10 << 11, 1}, + {10, 25 | 60 << 8, 5 | 12 << 11, 2}, + {11, 25 | 90 << 8, 5 | 18 << 11, 2}, + {12, 25 | 120 << 8, 5 | 24 << 11, 2}, + {13, 30 | 60 << 8, 2 | 4 << 11, 1}, + {14, 30 | 90 << 8, 2 | 6 << 11, 1}, + {15, 30 | 120 << 8, 2 | 8 << 11, 1}, + {16, 60 | 90 << 8, 2 | 3 << 11, 1}, + {17, 60 | 120 << 8, 2 | 4 << 11, 1}, + {18, 27 | 60 << 8, 4 | 9 << 11, 2}, + { 3, 6 | 60 << 8, 1 | 10 << 11, 0}, + { 2, 8 | 60 << 8, 2 | 15 << 11, 1}, + { 5, 10 | 60 << 8, 1 | 6 << 11, 0}, + { 8, 16 | 60 << 8, 4 | 15 << 11, 2}, + {14, 20 | 60 << 8, 2 | 6 << 11, 1}, + {16, 40 | 60 << 8, 2 | 3 << 11, 1}, + {18, 40 | 90 << 8, 4 | 9 << 11, 2}, + {13, 45 | 90 << 8, 2 | 4 << 11, 1}, + }; + + struct frc_lut_config video_config_table[IRIS_FRC_V2_LUT_TABLE_NUM+8] = { + { 1, 12 | 60 << 8, 1 | 5 << 11, 0}, + { 2, 12 | 90 << 8, 2 | 15 << 11, 1}, + { 3, 12 | 120 << 8, 1 | 10 << 11, 0}, + { 4, 15 | 60 << 8, 1 | 4 << 11, 1}, + { 5, 15 | 90 << 8, 1 | 6 << 11, 0}, + { 6, 15 | 120 << 8, 1 | 8 << 11, 0}, + { 19, 24 | 60 << 8, 4 | 10 << 11, 1}, + { 8, 24 | 90 << 8, 4 | 15 << 11, 2}, + { 9, 24 | 120 << 8, 2 | 10 << 11, 1}, + {10, 25 | 60 << 8, 5 | 12 << 11, 2}, + {11, 25 | 90 << 8, 5 | 18 << 11, 2}, + {12, 25 | 120 << 8, 5 | 24 << 11, 2}, + {13, 30 | 60 << 8, 2 | 4 << 11, 1}, + {14, 30 | 90 << 8, 2 | 6 << 11, 1}, + {15, 30 | 120 << 8, 2 | 8 << 11, 1}, + {16, 60 | 90 << 8, 2 | 3 << 11, 1}, + {17, 60 | 120 << 8, 2 | 4 << 11, 1}, + {18, 27 | 60 << 8, 4 | 9 << 11, 2}, + { 3, 6 | 60 << 8, 1 | 10 << 11, 0}, + { 2, 8 | 60 << 8, 2 | 15 << 11, 1}, + { 5, 10 | 60 << 8, 1 | 6 << 11, 0}, + { 8, 16 | 60 << 8, 4 | 15 << 11, 2}, + {14, 20 | 60 << 8, 2 | 6 << 11, 1}, + {16, 40 | 60 << 8, 2 | 3 << 11, 1}, + {18, 40 | 90 << 8, 4 | 9 << 11, 2}, + {13, 45 | 90 << 8, 2 | 4 << 11, 1}, + }; + + if (pcfg->rx_mode == DSI_OP_CMD_MODE) { + for (i = 0; i < IRIS_FRC_V2_LUT_TABLE_NUM+8; i++) { + if (inout_ratio == config_table[i].in_out_ratio) { + frc_setting->v2_lut_index = config_table[i].index; + frc_setting->v2_period_phasenum = config_table[i].period_phasenum; + frc_setting->v2_phaselux_idx_max = config_table[i].idx_max; + IRIS_LOGI("inout_ratio: %d", inout_ratio); + IRIS_LOGI("select frc lut index: %d", frc_setting->v2_lut_index); + IRIS_LOGI("select frc inout ratio: %d", frc_setting->v2_period_phasenum); + return true; + } + } + } else { + for (i = 0; i < IRIS_FRC_V2_LUT_TABLE_NUM+8; i++) { + if (inout_ratio == video_config_table[i].in_out_ratio) { + frc_setting->v2_lut_index = video_config_table[i].index; + frc_setting->v2_period_phasenum = video_config_table[i].period_phasenum; + frc_setting->v2_phaselux_idx_max = video_config_table[i].idx_max; + IRIS_LOGI("inout_ratio: %d", inout_ratio); + IRIS_LOGI("select frc lut index: %d", frc_setting->v2_lut_index); + IRIS_LOGI("select frc inout ratio: %d", frc_setting->v2_period_phasenum); + return true; + } + } + } + + return false; +} + +static u32 iris_get_vtotal(void) +{ + uint32_t *payload; + uint32_t vtotal; + + if (frc_setting->out_fps == HIGH_FREQ) + payload = iris_get_ipopt_payload_data(IRIS_IP_DTG, 0x01, 2); + else + payload = iris_get_ipopt_payload_data(IRIS_IP_DTG, 0x00, 2); + vtotal = payload[4] + payload[5] + payload[6] + payload[7]; + if (iris_display_vtotal != -1) + vtotal = iris_display_vtotal; + return vtotal; +} + +void iris_frc_mif_reg_set(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 val_frcc_reg5 = 0x3c000000, val_frcc_reg8 = 0x10000000, val_frcc_reg16 = 0x413120c8, val_frcc_reg17 = 0x8000; + u32 val_frcc_reg18 = 0x80000000, val_frcc_cmd_th = 0x8000, val_frcc_dtg_sync = 0; + u8 keep_th = 0, carry_th = 0, phase_map_en = 0; + u8 repeatp1_th = 0, repeatcf_th = 0; + u8 ts_frc_en = 0, three_mvc_en = 0; + u16 input_record_thr = 0, start_line; + u32 hsync_freq_out, hsync_freq_in; + u16 mvc_metarec_thr1 = 0, mvc_metarec_thr2 = 0; + u16 vfr_mvc_metagen_th1 = 0, vfr_mvc_metagen_th2 = 0; + u16 fi_repeatcf_th = 0; + u16 fmif_vd_hstride, fmif_dsy_hstride, fmif_mv_hstride; + u32 fmif_vd_offset, fmif_dsy_frm_offset, fmif_mv_frm_offset; + u16 mv_hres, mv_vres; + u8 max_fi_meta_fifo = 4; + u32 vtotal_frcc = iris_get_vtotal(); + u32 mvc_01phase_vcnt, dedicate_01phase_en = 0, mvc_01phase_metagen2, mvc_01phase_metagen, mvc_01phase_metarec; + u32 mvc_metagen_thr3, mvc_metarec_thr3, three_metagen_en = 1, three_metagen_fi_en = 0; + u32 frcc_teadj_th = 0x00282080; + u32 temp, temp0, m, n; + u32 frc_ratio = frc_setting->v2_period_phasenum; + u32 phase_teadj_en = 1; + u32 input_vtotal = iris_get_vtotal(); + u32 disp_vtotal = iris_get_vtotal(); + u32 memc_level = frc_setting->memc_level; + + IRIS_LOGI("out_fps: %d, vtotal: %d", frc_setting->out_fps, disp_vtotal); + + fmif_vd_hstride = iris_frc_video_hstride_calc(frc_setting->memc_hres, frc_setting->memc_dsc_bpp, 1); + fmif_vd_offset = fmif_vd_hstride * frc_setting->memc_vres * 8; + fmif_dsy_hstride = (((frc_setting->memc_hres + 1) / 2) * 8 + 63) / 64; + fmif_dsy_frm_offset = fmif_dsy_hstride * (frc_setting->memc_vres * 5 / 10) * 8; + fmif_mv_hstride = ((frc_setting->memc_hres + 15) / 16 * 32 + 63) / 64; + fmif_mv_frm_offset = fmif_mv_hstride * CEILING(frc_setting->memc_vres, 16) * 8; + mv_hres = CEILING(frc_setting->memc_hres, 16); + mv_vres = CEILING(frc_setting->memc_vres, 16); + + if (!(pcfg->dual_test & 0x2)) + frc_setting->mv_baseaddr = 0x300000 - (4+frc_setting->mv_buf_num) * fmif_mv_frm_offset; + IRIS_LOGI("mv_baseaddr: %x, offset: %x", frc_setting->mv_baseaddr, fmif_mv_frm_offset); + if ((frc_setting->video_baseaddr + 3 * fmif_vd_offset) > frc_setting->mv_baseaddr) { + IRIS_LOGE("buffer check failed!"); + IRIS_LOGE("video_baseaddr: %x, offset: %x", frc_setting->video_baseaddr, fmif_vd_offset); + IRIS_LOGE("mv_baseaddr: %x, offset: %x", frc_setting->mv_baseaddr, fmif_mv_frm_offset); + } + + if (frc_setting->disp_hres != frc_setting->memc_hres) + start_line = 5; + else + start_line = 0; + + hsync_freq_in = frc_setting->out_fps * input_vtotal; + hsync_freq_out = frc_setting->out_fps * disp_vtotal; + + IRIS_LOGI(" print video enter fps = %d, output fps = %d.", frc_setting->in_fps, frc_setting->out_fps); + + carry_th = 5; + keep_th = 252; + repeatp1_th = 5; + repeatcf_th = 252; + fi_repeatcf_th = 252; + input_record_thr = (input_vtotal / 8 + start_line) * hsync_freq_out / hsync_freq_in; + mvc_metarec_thr1 = (input_vtotal * 5 / 8 + start_line) * hsync_freq_out / hsync_freq_in; + mvc_metarec_thr2 = (input_vtotal * 7 / 8 + start_line) * hsync_freq_out / hsync_freq_in; + vfr_mvc_metagen_th1 = (input_vtotal / 8 + start_line) * hsync_freq_out / hsync_freq_in; + vfr_mvc_metagen_th2 = (input_vtotal * 6 / 8 + start_line) * hsync_freq_out / hsync_freq_in; + + temp = frc_setting->out_fps; + temp0 = frc_setting->in_fps; + while (temp%temp0 != 0) { + m = temp%temp0; + temp = temp0; + temp0 = m; + } + + m = frc_setting->out_fps/temp0; + n = frc_setting->in_fps/temp0; + + if ((m/n) == 4) { + vtotal_frcc = (disp_vtotal * 2)/3; + IRIS_LOGI(" print m = %d, n = %d, vtotal_frcc = %d.", m, n, vtotal_frcc); + } else if ((m/n) == 5 || (m/n) == 6) { + vtotal_frcc = (disp_vtotal * (m - 1))/m; + IRIS_LOGI(" print m = %d, n = %d, vtotal_frcc = %d.", m, n, vtotal_frcc); + } else if ((m/n) > 6) { + temp = (m + n - 1)/n; + temp = (temp)/2; + temp0 = (m/n)-1; + temp0 = temp0 * disp_vtotal; + vtotal_frcc = (2*temp0)/(2*temp + 3); + IRIS_LOGI(" print m = %d, n = %d, vtotal_frcc = %d.", m, n, vtotal_frcc); + } + + mvc_01phase_vcnt = disp_vtotal; + mvc_01phase_metagen = 20; + mvc_01phase_metarec = mvc_01phase_metagen + disp_vtotal/4; + mvc_01phase_metagen2 = mvc_01phase_metarec + 10; + + vfr_mvc_metagen_th1 = 50; + vfr_mvc_metagen_th2 = vfr_mvc_metagen_th1 + disp_vtotal/4; + mvc_metagen_thr3 = vfr_mvc_metagen_th2 + disp_vtotal/4; + + mvc_metarec_thr1 = vfr_mvc_metagen_th1 + disp_vtotal/5; + mvc_metarec_thr2 = vfr_mvc_metagen_th2 + disp_vtotal/5; + mvc_metarec_thr3 = mvc_metagen_thr3 + disp_vtotal/5; + + switch (frc_setting->in_fps) { + case 24: + three_mvc_en = 1; + if (frc_setting->out_fps == 90) + max_fi_meta_fifo = 6; + else + max_fi_meta_fifo = 4; + + if (frc_setting->out_fps == 120) { + three_mvc_en = 0; + max_fi_meta_fifo = 6; + three_metagen_en = 0; + dedicate_01phase_en = 1; + } + break; + case 30: + if (pcfg->frc_low_latency) { + three_mvc_en = 0; + max_fi_meta_fifo = 1; + phase_teadj_en = 0; + three_metagen_en = 0; + frc_ratio = 0x801; + } else if (frc_setting->out_fps == 120) { + three_mvc_en = 0; + max_fi_meta_fifo = 6; + three_metagen_en = 0; + dedicate_01phase_en = 1; + } else { + three_mvc_en = 1; + max_fi_meta_fifo = 3; + frcc_teadj_th = 0x280880; + if (frc_setting->out_fps == 90) + max_fi_meta_fifo = 5; + else + max_fi_meta_fifo = 3; + } + break; + case 25: + three_mvc_en = 1; + max_fi_meta_fifo = 5; + if (frc_setting->out_fps == 120) { + three_mvc_en = 0; + max_fi_meta_fifo = 6; + three_metagen_en = 0; + dedicate_01phase_en = 1; + } + break; + case 15: + three_mvc_en = 0; + max_fi_meta_fifo = 6; + three_metagen_en = 0; + dedicate_01phase_en = 1; + //three_metagen_fi_en = 1; + break; + case 6: + case 8: + case 10: + case 12: + three_mvc_en = 0; + max_fi_meta_fifo = 6; + dedicate_01phase_en = 1; + three_metagen_en = 0; + break; + case 16: + three_mvc_en = 1; + max_fi_meta_fifo = 6; + break; + case 20: + if (pcfg->frc_low_latency) { + three_mvc_en = 0; + max_fi_meta_fifo = 1; + phase_teadj_en = 0; + three_metagen_en = 0; + frc_ratio = 0x801; + } else { + three_mvc_en = 1; + max_fi_meta_fifo = 4; + } + break; + case 40: + if (pcfg->frc_low_latency) { + max_fi_meta_fifo = 4; + phase_teadj_en = 1; + three_mvc_en = 1; + three_metagen_en = 0; + } + break; + case 45: + if (pcfg->frc_low_latency) { + three_mvc_en = 0; + max_fi_meta_fifo = 1; + phase_teadj_en = 0; + three_metagen_en = 0; + frc_ratio = 0x801; + } + break; + case 60: + if (pcfg->frc_low_latency) { + max_fi_meta_fifo = 2; + frc_ratio = 0x801; + phase_teadj_en = 0; + three_mvc_en = 0; + three_metagen_en = 0; + } + break; + default: + three_mvc_en = 1; + max_fi_meta_fifo = 4; + break; + } + + memc_level = frc_setting->memc_level; + if (frc_setting->memc_osd && (memc_level > 2)) + memc_level = 2; + val_frcc_reg5 += carry_th + (keep_th << 8) + (phase_map_en << 16) + (memc_level << 17); + val_frcc_reg8 += repeatcf_th + (repeatp1_th << 8); + iris_val_frcc_reg8 = val_frcc_reg8; + val_frcc_reg8 |= 0x40000000; + val_frcc_reg16 += (three_mvc_en << 15) + (ts_frc_en << 31); + val_frcc_reg17 += input_record_thr + (vtotal_frcc << 16); + val_frcc_reg18 += mvc_metarec_thr1 + (mvc_metarec_thr2 << 16); + val_frcc_cmd_th += vfr_mvc_metagen_th1 + (vfr_mvc_metagen_th2 << 16); + val_frcc_dtg_sync += fi_repeatcf_th << 16; + + + //iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG0, 0x02122369, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG1, 0x80280014 + (memc_level << 25), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG2, (0x96100043 | (iris_dynamic_sadgain_mid << 10) | (iris_dynamic_sadgain_low << 16)), 0); + if (pcfg->rx_mode == DSI_OP_CMD_MODE) + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG3, (0x18002100 | iris_dynamic_sadcore_mid | (iris_dynamic_sadcore_low << 6) + | (iris_dynamic_outgain_mid << 18) | (iris_dynamic_outgain_low << 24)) + (1 << 30), 0); + else + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG3, 0x18602104, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG4, 0x000C2020 | (iris_dynamic_outcore_mid << 6) | (iris_dynamic_outcore_low << 12), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG5, val_frcc_reg5, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG6, 0x028003C0, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG7, 0x20000000 | frc_ratio, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG8, val_frcc_reg8, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG9, 0x3FFF3FFF, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG10, fmif_vd_offset, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG11, 0x380000, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG12, fmif_dsy_frm_offset, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG13, fmif_dsy_hstride + (fmif_mv_hstride << 16), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG14, frc_setting->mv_baseaddr, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG15, fmif_mv_frm_offset, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG16, val_frcc_reg16, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG17, val_frcc_reg17, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG18, val_frcc_reg18, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CMD_MOD_TH, val_frcc_cmd_th, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_DTG_SYNC, val_frcc_dtg_sync, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_SWITCH_CTRL, 0x8000000a, 0); + if (pcfg->frc_setting.short_video == 2) + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_SWFBK_CTRL, 0x00000080, 0); + else if (pcfg->frc_setting.short_video == 1) + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_SWFBK_CTRL, 0x00000040, 0); + else + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_SWFBK_CTRL, 0x00000000, 0); +#if 0 + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_TEOFFSET_CTRL, 0x00000000, 0); +#else + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_01PHASE_CTRL0, mvc_01phase_vcnt | dedicate_01phase_en << 15 | mvc_01phase_metagen2 << 16, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_01PHASE_CTRL1, mvc_01phase_metagen | mvc_01phase_metarec << 16, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_TEOFFSET_CTRL, 0x00000060 | phase_teadj_en, 0); + // enable frame drop threshold 4 + if (iris_frc_var_disp && !pcfg->osd_enable) { + if (iris_frc_var_disp == 1) { + if (pcfg->tx_mode == DSI_OP_CMD_MODE) + frc_setting->frcc_pref_ctrl = 0x00018012; + else + frc_setting->frcc_pref_ctrl = 0x00018912; + } else { + frc_setting->frcc_pref_ctrl = 0x00018010; + } + } else { + if (iris_frc_pt_switch_on) + frc_setting->frcc_pref_ctrl = 0x0001a011; + else + frc_setting->frcc_pref_ctrl = 0x00018010; + } + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_PERF_CTRL, frc_setting->frcc_pref_ctrl, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_TEOFFSET_ADJ, 0x00000000, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_TEADJ_TH, frcc_teadj_th, 0); + if (iris_frc_pt_switch_on) { + u32 mntswitch_th = (iris_mtnsw_low_th & 0xf) | ((iris_mtnsw_high_th & 0xf) << 4); + + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_MNTSWITCH_TH, mntswitch_th, 0); + } else + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_MNTSWITCH_TH, 0x00000000, 0); + if (iris_frc_fallback_disable) + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_EXT_MOTION, 0x10, 0); + else + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_EXT_MOTION, iris_frc_mnt_level, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_EXT_TE_OFFSET, 0x00000000, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_PHASELUT_CLIP, 0x0000fc05 | frc_setting->v2_phaselux_idx_max<<16, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_RW_PROT_TH, 0x00000080, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REC_META_CTRL, max_fi_meta_fifo, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_METAGEN3, mvc_metagen_thr3 | mvc_metarec_thr3 << 16 | + three_metagen_fi_en << 30 | three_metagen_en << 31, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_FRCPT_SWITCH_CTRL, iris_frcpt_switch_th, 0); +#endif + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REG_SHDW, 0x00000002, 0); + + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + IMIF_MODE_CTRL, 0x4 + ((frc_setting->memc_vres * 3 / 4) << 16), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + IMIF_DW_PER_LINE, fmif_vd_hstride, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + IMIF_VSIZE, (frc_setting->memc_vres), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + IMIF_SW_UPDATE_EN, 0x00000001, 0); + + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + MMIF_CTRL1, 0x00402000, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + MMIF_CTRL2, 0x8 + (disp_vtotal << 16), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + MMIF_PHASE1_BA, + frc_setting->mv_baseaddr + fmif_mv_frm_offset * (2 + frc_setting->mv_buf_num), 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + MMIF_PHASE0_BA, frc_setting->mv_baseaddr + fmif_mv_frm_offset * frc_setting->mv_buf_num, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + MMIF_UPDATE, 0x00000001, 0); + + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_CTRL, 0xFF004034, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_VD_FRM_ATTRIBUTE0, (0x10 << 16) + fmif_vd_hstride, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_VD_FRM_ATTRIBUTE1, (0x40 << 16) + frc_setting->memc_vres, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_MV_FRM_ATTRIBUTE0, (mv_hres << 16) + mv_vres, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_MV_FRM_ATTRIBUTE1, (0x4 << 16) + fmif_mv_hstride, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FMIF_REG_SHDW, 0x00000002, 0); + +} + +void iris_gmd_reg_set(void) +{ + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_GAIN, 0x0000C488, 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_FILT, 0x00000000, 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_ACCUM, 0x00000659, 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_SHIFT, 0x00000070, 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_START, 0x00000000, 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_STOP, frc_setting->memc_hres + (frc_setting->memc_vres << 16), 0); + iris_frc_reg_add(IRIS_GMD_ADDR + GMD_CTRL, 0x00000011, 0); +} + +void iris_fbd_reg_set(void) +{ + iris_frc_reg_add(IRIS_FBD_ADDR + FILMBD_RESOLUTION, (frc_setting->memc_hres / 2) + ((frc_setting->memc_vres / 2) << 16), 0); + iris_frc_reg_add(IRIS_FBD_ADDR + FILMBD_WIN_STOP_SET, frc_setting->memc_hres + (frc_setting->memc_vres << 16), 0); + iris_frc_reg_add(IRIS_FBD_ADDR + FILMBD_TOP_CTRL, 0x00010025, 0); + +} + +void iris_cad_reg_set(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + iris_frc_reg_add(IRIS_CAD_ADDR + NEW_FRM_FLG_DET_1, 0x06920311, 0); + iris_frc_reg_add(IRIS_CAD_ADDR + CAD_DET_BASIC_CAD, 0x0000010c, 0); + iris_frc_reg_add(IRIS_CAD_ADDR + CAD_DET_STVT, 0x00004083, 0); + iris_frc_reg_add(IRIS_CAD_ADDR + CAD_DET_BAD_EDIT, 0x00011255, 0); + iris_frc_reg_add(IRIS_CAD_ADDR + CAD_DET_VOF_0, 0x096823C1, 0); + iris_frc_reg_add(IRIS_CAD_ADDR + DUMMY, 0x000000F1, 0); + if (pcfg->rx_mode == DSI_OP_VIDEO_MODE) { + switch (frc_setting->in_fps) { + case 24: + case 30: + iris_frc_reg_add(IRIS_CAD_ADDR + COMMON, 0x00000079, 0); + break; + default: + iris_frc_reg_add(IRIS_CAD_ADDR + COMMON, 0x00000078, 0); + break; + } + } + + iris_frc_reg_add(IRIS_CAD_ADDR + SW_DONE, 0x00000001, 1); + +} + +void iris_mvc_reg_set(void) +{ + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_CTRL_0, 0x00524480, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_TOP_CTRL_0, 0x00000012, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + GLB_MVSELECT_1, 0x9C1F7F20, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + GLB_MVSELECT_2, 0x08448082, 0); + if (iris_mvc_tuning & 1) + iris_frc_reg_add(IRIS_MVC_ADDR + HALORED_2, 0x2148091c, 0); + else + iris_frc_reg_add(IRIS_MVC_ADDR + HALORED_2, 0x2148091f, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_POSTFILT_1, 0x208F0012, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_SAD_2, 0x622FFFFF, 0); //todo + if (frc_setting->memc_hres < 300) { // FRC resolution 270x480 in FPGA verfication + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_3, 0x00640000, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_4, 0x00000064, 0); + } else { + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_1, 0x00000103, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_2, 0x00410204, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_3, 0x00640000, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_CTRL_4, 0x00000320, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_STEP, 0x01020082, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HISTMV_BASE, 0x24121005, 0); + } + + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_POSTGLBDC_0, 0x00541204, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_OSDDET_0, 0x40642408, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_OSDDET_1, 0x20880320, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + HLMD_CTRL, 0xB98C820B, 0); + iris_frc_reg_add(IRIS_MVC_ADDR + MVC_SW_UPDATE, 0x00000001, 0); +} + +void iris_fi_reg_set(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 max_search_range, val_range_ctrl; + u32 vrange_top, vrange_bot; + u32 hres = (frc_setting->memc_hres / 4) * 4; + + if (frc_setting->memc_hres % 4) + hres += 4; + max_search_range = 0x20000 / hres - 4; + if (max_search_range > 510) + max_search_range = 510; + vrange_top = max_search_range / 2 - 1; + vrange_bot = max_search_range / 2; + // vrange_bot should be odd number + if (vrange_bot%2 == 0) { + vrange_bot -= 1; + vrange_top -= 1; + } + val_range_ctrl = vrange_top + (vrange_bot << 9) + (max_search_range << 18); + iris_frc_reg_add(IRIS_FI_ADDR + FI_RANGE_CTRL, val_range_ctrl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CLOCK_GATING, 0xff2c0, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_MODE_CTRL, 0x00004022 | iris_frc_label<<16 + | (iris_frc_demo_window ? 1:0), 0);// set flim label + if (pcfg->osd_on) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_MODE_RING, 0x780152, 0); + IRIS_LOGI("Dual channel!"); + } else { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_MODE_RING, 0xf05a52, 0); + IRIS_LOGI("singl channel!"); + } + + if (iris_frc_demo_window == 1) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_COL_SIZE, frc_setting->memc_hres << 16, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_ROW_SIZE, frc_setting->memc_vres << 15, 0); + } else if (iris_frc_demo_window == 2) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_COL_SIZE, frc_setting->memc_hres << 16, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_ROW_SIZE, frc_setting->memc_vres >> 1 + | frc_setting->memc_vres << 16, 0); + } else if (iris_frc_demo_window == 3) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_COL_SIZE, frc_setting->memc_hres << 15, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_ROW_SIZE, frc_setting->memc_vres << 16, 0); + } else if (iris_frc_demo_window == 4) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_COL_SIZE, frc_setting->memc_hres >> 1 + | frc_setting->memc_hres << 16, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_ROW_SIZE, frc_setting->memc_vres << 16, 0); + } else if (iris_frc_demo_window == 5) { + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_COL_SIZE, frc_setting->memc_hres << 16, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_DEMO_ROW_SIZE, frc_setting->memc_vres << 16, 0); + } + iris_fi_demo_window_cal(); + iris_frc_reg_add(IRIS_FI_ADDR + FI_VIDEO_BUF_CTRL, 0x00002000, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_V9_GENERIC_CTRL, 0xffffffff, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_MISC_CTRL, 0x00000008, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_CTRL, 0x00000019, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_COEF0, 0x08000800, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_COEF1, 0x00000800, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_COEF2, 0x0e307d40, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_COEF3, 0x7a480b38, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_COEF4, 0x00000000, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_OFFSET0, 0x00000000, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_OFFSET1, 0x00000000, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_CSC_OFFSET2, 0x00000000, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_SHDW_CTRL, 0x00000001, 1); // set last flag +} + +void iris_pwil_frc_ratio_and_01phase_set(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 temp, temp0, m, n; + u32 mvc_01phase = 1; + + temp = frc_setting->out_fps; + temp0 = frc_setting->in_fps; + while (temp % temp0 != 0) { + m = temp % temp0; + temp = temp0; + temp0 = m; + } + + m = frc_setting->out_fps/temp0; + n = frc_setting->in_fps/temp0; + switch (frc_setting->in_fps) { + case 30: + case 45: + case 60: + if (!pcfg->frc_low_latency) + mvc_01phase = 1; + else + mvc_01phase = 0; + break; + default: + break; + } + mspwil_par.out_fps_ratio = m; + mspwil_par.in_fps_ratio = n; + mspwil_par.mvc_01phase = mvc_01phase; + mspwil_par.ratio_update = 1; + mspwil_par.mvc_01phase_update = 1; +} + +void iris_pwil_frc_ratio_and_01phase_ocp_set(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 temp, temp0, m, n; + u32 mvc_01phase = 1; + + temp = frc_setting->out_fps; + temp0 = frc_setting->in_fps; + while (temp % temp0 != 0) { + m = temp % temp0; + temp = temp0; + temp0 = m; + } + + m = frc_setting->out_fps/temp0; + n = frc_setting->in_fps/temp0; + switch (frc_setting->in_fps) { + case 30: + case 45: + case 60: + if (!pcfg->frc_low_latency) + mvc_01phase = 1; + else + mvc_01phase = 0; + break; + default: + break; + } + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_DPCD_CTRL, m<<24, 0); + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_FBO_CTRL, 0x800 | (n<<8), 0); + if (pcfg->rx_mode == DSI_OP_CMD_MODE) + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_VIDEO_CTRL2, 0x12061b09 | (mvc_01phase<<31), 0); + else + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_VIDEO_CTRL2, 0x12061b0d | (mvc_01phase<<31), 0); + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_REG_UPDATE, 0x100, 1); +} + +void iris_frc_mode_prepare(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->frc_setting_ready = iris_frc_setting_check(); + if (!pcfg->frc_setting_ready) { + IRIS_LOGE("Can't find correct frc setting!"); + return; + } + + if (!iris_frc_dynamic_off) { + if (frc_setting->in_fps_configured == frc_setting->in_fps) { + IRIS_LOGI("FRC setting has been configured: %d", frc_setting->in_fps); + return; + } + } + iris_frc_reg_add(IRIS_PROXY_MB5, 0x00000000, 0); + /* FRC_MIF */ + iris_frc_mif_reg_set(); + + /* GMD */ + iris_gmd_reg_set(); + + /* FBD */ + iris_fbd_reg_set(); + + /* CAD */ + iris_cad_reg_set(); + + /* MVC */ + iris_mvc_reg_set(); + + /* FI */ + iris_fi_reg_set(); + + /* FI_DS to improve 444 to 422 down-sample quality*/ + iris_frc_reg_add(0xf2080000, 0x000a003e, 1); + + /* send frc lut */ + iris_send_ipopt_cmds(FRC_PHASE_LUT, 0); + iris_send_ipopt_cmds(FRC_PHASE_LUT, frc_setting->v2_lut_index); + + frc_setting->in_fps_configured = frc_setting->in_fps; +} + +static uint32_t iris_pwil_disp_ctrl0(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct dsi_display_mode *display_mode; + u8 mode = pcfg->pwil_mode; + bool osd_enable = pcfg->osd_enable; + u32 disp_ctrl0 = 0; + + if (mode == PT_MODE) { + disp_ctrl0 = 0; + disp_ctrl0 |= 0x10000; + } else if (mode == RFB_MODE) { + disp_ctrl0 = 3; + disp_ctrl0 |= 0x10000; + } else if (mode == FRC_MODE) { + disp_ctrl0 = 1; + disp_ctrl0 |= 0x20000; + } + if (osd_enable) + disp_ctrl0 |= 0x10000000; + + if (pcfg->panel && pcfg->panel->cur_mode) { + display_mode = pcfg->panel->cur_mode; + if (display_mode->priv_info && display_mode->priv_info->dsc_enabled) + disp_ctrl0 |= 0x100; + } + return disp_ctrl0; +} + +static bool iris_get_tx_reserve_0(uint32_t *tx_reserve_0) +{ + uint32_t *payload = NULL; + struct iris_ip_opt *popt = iris_find_ip_opt(IRIS_IP_TX, 0x00); + + if (popt != NULL) { + if (popt->cmd->msg.tx_len >= 19) { // length + payload = iris_get_ipopt_payload_data(IRIS_IP_TX, 0x00, 2); + if (payload) { + if (payload[15] == IRIS_TX_RESERVE_0) { + *tx_reserve_0 = payload[16]; + return true; + } + IRIS_LOGE("cannot find IRIS_TX_RESERVE_0, [15]: %x, [16]: %x", + payload[15], payload[16]); + } else { + IRIS_LOGE("cannot find IRIS_TX_RESERVE_0, payload NULL"); + } + } else { + IRIS_LOGE("TX cmd length: %zu is less than 19.", popt->cmd->msg.tx_len); + } + } + return false; +} + +static void iris_ms_pwil_ocp_update(bool force_repeat, bool var_disp_in_frc_post) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + uint32_t pwil_ad_frc_info; + uint32_t pwil_datapath; + uint32_t pwil_ctrl; + uint32_t disp_ctrl0 = iris_pwil_disp_ctrl0(); + uint32_t tx_reserve_0 = 0x00c840c6; + int temp = 0; + + uint32_t *payload = NULL; + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0x23, 2); + pwil_ad_frc_info = payload[0]; + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_ctrl = payload[0]; + pwil_datapath = payload[2]; + IRIS_LOGI("%s, pwil_ctrl=%x, pwil_datapath: %x", __func__, pwil_ctrl, pwil_datapath); + IRIS_LOGI("%s, pwil_ad_frc_info=%x", __func__, pwil_ad_frc_info); + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_CTRL, pwil_ctrl, 0); + iris_frc_reg_add(IRIS_PWIL_ADDR + DATA_PATH_CTRL, pwil_datapath, 0); + if (iris_get_tx_reserve_0(&tx_reserve_0)) { + if (pwil_ad_frc_info & (1<<8)) // frc_var_disp flag + tx_reserve_0 |= 1<<28; + else + tx_reserve_0 &= ~(1<<28); + IRIS_LOGI("%s, tx_reserve_0=%x", __func__, tx_reserve_0); + iris_frc_reg_add(IRIS_TX_RESERVE_0, tx_reserve_0, 0); + } + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_PIAD_FRC_INFO, pwil_ad_frc_info, 0); + if (var_disp_in_frc_post && !pcfg->osd_enable) { + if (pcfg->tx_mode == DSI_OP_CMD_MODE) + frc_setting->frcc_pref_ctrl = 0x00018012; + else + frc_setting->frcc_pref_ctrl = 0x00018912; + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_PERF_CTRL, frc_setting->frcc_pref_ctrl, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REG_SHDW, 0x00000002, 0); + } + if (force_repeat && (pcfg->rx_mode == pcfg->tx_mode)) + disp_ctrl0 |= 0x40; + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_DISP_CTRL0, disp_ctrl0, 1); + + if (mspwil_par.ratio_update) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF4, 2); + temp = payload[9]; + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_DPCD_CTRL, temp, 0); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xD0, 2); + temp = payload[5]; + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_FBO_CTRL, temp, 0); + } + + if (mspwil_par.mvc_01phase_update) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xB0, 2); + temp = payload[2]; + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_VIDEO_CTRL2, temp, 0); + } + iris_frc_reg_add(IRIS_PWIL_ADDR + PWIL_REG_UPDATE, 0x100, 1); +} + +static void iris_dtg_te_n2m_mode(int frc) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 temp, temp0, m, n; + u32 in_fps, out_fps; + + if (frc && pcfg->n2m_enable) { + out_fps = frc_setting->out_fps; + in_fps = frc_setting->in_fps; + } else { + out_fps = pcfg->panel_te; + in_fps = pcfg->ap_te; + } + + temp = out_fps; + temp0 = in_fps; + while (temp % temp0 != 0) { + m = temp % temp0; + temp = temp0; + temp0 = m; + } + m = out_fps/temp0; + n = in_fps/temp0; + + if (iris_te_dly_frc != -1) + iris_frc_reg_add(IRIS_DTG_ADDR + DTG_REG_26, iris_te_dly_frc, 0); + iris_frc_reg_add(IRIS_DTG_ADDR + DTG_REG_41, m | n<<8 | 0x80000000, 0); + if (frc && in_fps == 40 && out_fps == 90) // keep previouse value + iris_frc_reg_add(IRIS_DTG_ADDR + DTG_REG_45, 0x80000004, 0); + else + iris_frc_reg_add(IRIS_DTG_ADDR + DTG_REG_45, 0x80000005, 0); + iris_frc_reg_add(IRIS_DTG_ADDR + DTG_UPDATE, 0x0000000e, 1); + + // update DTG dtsi + if (frc == 0) { + if (pcfg->panel_te == 90) + iris_set_ipopt_payload_data(IRIS_IP_DTG, 0x00, 2+41, m | n<<8 | 0x80000000); + else + iris_set_ipopt_payload_data(IRIS_IP_DTG, 0x01, 2+41, m | n<<8 | 0x80000000); + } +} + +static void iris_rfb_mode_prepare(void) +{ + //struct iris_cfg *pcfg = iris_get_cfg(); + // disable variable display + iris_frc_reg_add(IRIS_PROXY_MB5, 0x00000001, 0); + if (iris_frc_var_disp) { + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_PERF_CTRL, 0x00019f10, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REG_SHDW, 0x00000002, 1); + } else if (iris_frc_pt_switch_on) { + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_MNTSWITCH_TH, 0x00000000, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_FRCPT_SWITCH_CTRL, iris_frcpt_switch_th & ~0x20, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REG_SHDW, 0x00000003, 1); + //iris_pwil_frc_pt_set(0); + } +} + +static void iris_download_mcu_code(void) +{ + iris_send_ipopt_cmds(APP_CODE_LUT, 0); + IRIS_LOGI("%s", __func__); +} + +static void iris_mcu_sw_reset(u32 reset) +{ + iris_frc_reg_add(IRIS_SYS_ADDR + MCU_SW_RESET, reset, 1); +} + +static void iris_proxy_mcu_stop(void) +{ + iris_frc_reg_add(IRIS_UNIT_CTRL_INTEN, 0x0, 0x0); + iris_frc_reg_add(IRIS_PROXY_MB1, 0x1, 0x1); +} + +static bool iris_mcu_is_stop(void) +{ + if (iris_mcu_stop_check) { + // if stress test passed, no need check mcu stop status + // u32 proxy_mb1 = iris_ocp_read(IRIS_PROXY_MB1, DSI_CMD_SET_STATE_HS); + // u32 mcu_info_1 = iris_ocp_read(IRIS_MCU_INFO_1, DSI_CMD_SET_STATE_HS); + u32 mcu_info_2 = iris_ocp_read(IRIS_MCU_INFO_2, DSI_CMD_SET_STATE_HS); + + IRIS_LOGI("mcu_info_2: %x", mcu_info_2); + if (((mcu_info_2>>8)&0x3) == 3) + return true; + else + return false; + } else { + return true; + } +} + +static void iris_blending_timeout_set(int frc) { + struct iris_cfg *pcfg = iris_get_cfg(); + bool high; + u32 framerate = pcfg->panel->cur_mode->timing.refresh_rate; + if ((framerate == HIGH_FREQ) && (pcfg->panel->cur_mode->timing.v_active == FHD_H)) + high = true; + else + high = false; + if (frc) { + iris_send_ipopt_cmds(IRIS_IP_BLEND, high? 0x31 : 0x11); // blending: frc ocp + iris_send_ipopt_cmds(IRIS_IP_BLEND, high? 0x30 : 0x10); // blending: frc + } else { + iris_send_ipopt_cmds(IRIS_IP_BLEND, 0x21); // blending: pt ocp + iris_send_ipopt_cmds(IRIS_IP_BLEND, 0x20); // blending: pt + } +} + +static void iris_dport_output_mode(int mode) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + uint32_t *payload = NULL; + uint32_t dport_ctrl0; + static u32 write_data[4]; + + payload = iris_get_ipopt_payload_data(IRIS_IP_DPORT, 0xF0, 2); + dport_ctrl0 = payload[0]; + dport_ctrl0 &= ~0xc000; + dport_ctrl0 |= (mode & 0x3) << 14; + // disable dport output before FRC enter command + write_data[0] = IRIS_DPORT_CTRL0; + write_data[1] = dport_ctrl0; + write_data[2] = IRIS_DPORT_REGSEL; + write_data[3] = 0x1; + iris_ocp_write_mult_vals(4, write_data); + pcfg->dport_output_mode = mode; +} + +static void iris_mspwil_par_clean(void) +{ + mspwil_par.frc_var_disp = -1; + mspwil_par.frc_pt_switch_on = -1; + mspwil_par.cmd_disp_on = -1; + mspwil_par.ratio_update = 0; + mspwil_par.mvc_01phase_update = 0; +} + +void iris_mode_switch_proc(u32 mode) +{ + bool force_repeat; + struct iris_cfg *pcfg = iris_get_cfg(); + + if (!pcfg->frc_enable) + return; + + frc_setting = &pcfg->frc_setting; + iris_frc_cmd_payload_init(); + iris_mspwil_par_clean(); + + if (mode == IRIS_MODE_FRC_PREPARE) { + if(pcfg->dual_setting) { + iris_frc_var_disp = iris_frc_var_disp_dual; // enable vfr in dual case by default + iris_frc_pt_switch_on = 0; // disable frc+pt in dual case + } else { + iris_frc_var_disp = iris_frc_var_disp_dbg; + iris_frc_pt_switch_on = iris_frc_pt_switch_on_dbg; + } + + iris_ulps_source_sel(ULPS_NONE); + /*Power up FRC domain*/ + iris_pmu_frc_set(true); + /*dma trigger frc dsc_unit, for FPGA only */ + //iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe6); + + /*Power up BSRAM domain if need*/ + iris_pmu_bsram_set(true); + + if (pcfg->pwil_mode == PT_MODE) { + /* power up DSC_UNIT */ + iris_pmu_dscu_set(true); + if (!(pcfg->dual_test & 0x1)) + iris_frc_dsc_setting(pcfg->dual_setting); + else + iris_send_ipopt_cmds(IRIS_IP_DMA, 0xe8); + } + mspwil_par.frc_var_disp = iris_frc_var_disp == 1; + mspwil_par.frc_pt_switch_on = iris_frc_pt_switch_on; + mspwil_par.cmd_disp_on = 0; + iris_pwil_frc_ratio_and_01phase_set(); + iris_ms_pwil_dma_update(&mspwil_par); + iris_ms_pwil_ocp_update(false, false); + iris_dtg_te_n2m_mode(1); + iris_frc_mode_prepare(); + if (iris_mcu_enable != 0) { + if (!pcfg->mcu_code_downloaded) { + iris_download_mcu_code(); + pcfg->mcu_code_downloaded = true; + } + } + if (iris_frc_fallback_disable) { // disable mcu during mcu + iris_mcu_sw_reset(1); + } + iris_blending_timeout_set(1); + } else if (mode == IRIS_MODE_FRC2RFB) { + iris_rfb_mode_enter(); + iris_pwil_sdr2hdr_resolution_set(false); + if (iris_mcu_enable) + iris_proxy_mcu_stop(); + } else if (mode == IRIS_MODE_RFB2FRC) { + if (pcfg->frc_setting_ready) { + if (iris_dport_output_toggle) + iris_dport_output_mode(0); + iris_frc_mode_enter(); + iris_pwil_sdr2hdr_resolution_set(true); + } else + IRIS_LOGE("frc setting not ready!"); + } else if (mode == IRIS_MODE_RFB_PREPARE) { + iris_rfb_mode_prepare(); + mspwil_par.cmd_disp_on = 0; + iris_ms_pwil_dma_update(&mspwil_par); + // no need set force repeat in video mode, single channel only in video mode + force_repeat = pcfg->rx_mode ? true : false; + if (iris_frc_pt_switch_on) + force_repeat = false; + iris_ms_pwil_ocp_update(force_repeat, false); + } else if (mode == IRIS_MODE_FRC_POST) { + if (iris_frc_var_disp == 2) { + mspwil_par.frc_var_disp = 1; + iris_ms_pwil_dma_update(&mspwil_par); + iris_ms_pwil_ocp_update(false, true); + } + if (pcfg->osd_enable) + iris_psf_mif_efifo_set(pcfg->pwil_mode, pcfg->osd_enable); + if (iris_mcu_enable) + iris_mcu_sw_reset(0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_CTRL_REG8, iris_val_frcc_reg8, 0); + iris_frc_reg_add(IRIS_FRC_MIF_ADDR + FRCC_REG_SHDW, 0x00000002, 0); + } else if (mode == IRIS_MODE_RFB_PREPARE_DELAY) { + if (iris_frc_var_disp) { + mspwil_par.frc_var_disp = 0; + iris_ms_pwil_dma_update(&mspwil_par); + force_repeat = pcfg->rx_mode ? true : false; + iris_ms_pwil_ocp_update(force_repeat, false); + } + iris_blending_timeout_set(0); + } else if (mode == IRIS_MODE_RFB_POST) { + if (iris_mcu_enable == 1) { + if (pcfg->rx_mode == 1) {// command mode + if (iris_mcu_is_stop()) + iris_mcu_sw_reset(1); + else + IRIS_LOGI("iris mcu not in stop, can't reset mcu"); + } else { + iris_mcu_sw_reset(1); + } + } + if (iris_frc_fallback_disable) // disable mcu during mcu + iris_mcu_sw_reset(0); + iris_dtg_te_n2m_mode(0); + /*Power down FRC domain*/ + iris_pmu_frc_set(false); + if (pcfg->pwil_mode == RFB_MODE) { + mspwil_par.cmd_disp_on = 1; + iris_pwil_cmd_disp_mode_set(true); + } else if (pcfg->pwil_mode == PT_MODE) { + /* power down DSC_UNIT */ + iris_pmu_dscu_set(false); + } + + /*Power down BSRAM domain if in PT single channel*/ + if ((pcfg->pwil_mode == PT_MODE) && (pcfg->osd_enable == false)) + iris_pmu_bsram_set(false); + + if ((pcfg->osd_enable == false) && (iris_i3c_status_get() == false)) + iris_ulps_source_sel(ULPS_MAIN); + } + + if ((mode == IRIS_MODE_FRC_POST) || + (mode == IRIS_MODE_RFB_PREPARE_DELAY) || + (mode == IRIS_MODE_RFB_POST)) { + // just for set parameters + } else + pcfg->switch_mode = mode; + + if (mode == IRIS_MODE_FRC_POST) { + if (iris_frc_var_disp) + pcfg->dynamic_vfr = true; + atomic_set(&pcfg->video_update_wo_osd, 0); + } else if (mode == IRIS_MODE_RFB_PREPARE) + pcfg->dynamic_vfr = false; + iris_frc_cmd_payload_release(); +} + +static int iris_get_mode(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + int switch_mode; + int pwil_mode = -1; + u32 pwil_status = iris_ocp_read(IRIS_PWIL_ADDR + PWIL_STATUS, DSI_CMD_SET_STATE_HS); + u32 pwil_mode_state = pwil_status; + + pwil_mode_state >>= 5; + pwil_mode_state &= 0x3f; + if (pwil_mode_state == 2) + pwil_mode = PT_MODE; + else if (pwil_mode_state == 4) + pwil_mode = RFB_MODE; + else if (pwil_mode_state == 8) + pwil_mode = FRC_MODE; + + if (pwil_mode == PT_MODE) + switch_mode = IRIS_MODE_PT; + else if (pwil_mode == RFB_MODE) + switch_mode = IRIS_MODE_RFB; + else if (pwil_mode == FRC_MODE) + switch_mode = IRIS_MODE_FRC; + else + switch_mode = pcfg->switch_mode; + + if ((pcfg->dport_output_mode == 0) && (pwil_mode == FRC_MODE)) + iris_dport_output_mode(2); + + IRIS_LOGW("switch_mode: %d, pwil_mode: %d, pwil_status: %x", + switch_mode, pwil_mode, pwil_status); + + return switch_mode; +} + +void iris_fi_demo_window(u32 DemoWinMode) +{ + iris_frc_demo_window = DemoWinMode; + IRIS_LOGI("MEMC demo window mode !"); +} + +int32_t iris_fi_osd_protect_window(u32 Top_left_position, u32 bottom_right_position, u32 osd_window_ctrl, u32 Enable, u32 DynCompensate) +{ + int32_t rc = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + u32 temp0, temp1, temp2, temp3; + + if (osd_window_ctrl > 4) { + IRIS_LOGE("OSD protect window number only have 5."); + return -EINVAL; + } + + temp0 = Top_left_position & 0xffff; + temp1 = (Top_left_position >> 16) & 0xffff; + temp2 = bottom_right_position & 0xffff; + temp3 = (bottom_right_position >> 16) & 0xffff; + + if ((temp0 > (frc_setting->disp_hres - 1)) || (temp1 > (frc_setting->disp_vres - 1)) || (temp2 > (frc_setting->disp_hres - 1)) || (temp3 > (frc_setting->disp_vres - 1))) { + IRIS_LOGE("OSD protect window size error."); + return -EINVAL; + } + + if ((temp0 > temp2) || (temp1 > temp3)) { + IRIS_LOGE("OSD protect window begin point position is bigger than end point position."); + return -EINVAL; + } + + if (!DynCompensate) + pcfg->frc_setting.iris_osd_win_dynCompensate &= (~(1 << osd_window_ctrl)); + else + pcfg->frc_setting.iris_osd_win_dynCompensate |= (1 << osd_window_ctrl); + + if (!Enable) { + pcfg->frc_setting.iris_osd_window_ctrl &= (~(7 << (osd_window_ctrl * 3))); + } else { + pcfg->frc_setting.iris_osd_window_ctrl |= (1 << (osd_window_ctrl * 3)); + switch (osd_window_ctrl) { + case 0: + pcfg->frc_setting.iris_osd0_tl = Top_left_position; + pcfg->frc_setting.iris_osd0_br = bottom_right_position; + break; + case 1: + pcfg->frc_setting.iris_osd1_tl = Top_left_position; + pcfg->frc_setting.iris_osd1_br = bottom_right_position; + break; + case 2: + pcfg->frc_setting.iris_osd2_tl = Top_left_position; + pcfg->frc_setting.iris_osd2_br = bottom_right_position; + break; + case 3: + pcfg->frc_setting.iris_osd3_tl = Top_left_position; + pcfg->frc_setting.iris_osd3_br = bottom_right_position; + break; + case 4: + pcfg->frc_setting.iris_osd4_tl = Top_left_position; + pcfg->frc_setting.iris_osd4_br = bottom_right_position; + break; + default: + break; + } + } + return rc; +} + +void iris_fi_demo_window_cal(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + u32 osd0_tl, osd0_br, osd1_tl, osd1_br, osd2_tl, osd2_br; + u32 osd3_tl, osd3_br, osd4_tl, osd4_br; + u32 temp0, temp1, temp2, temp3; + + //osd window 0 + temp0 = pcfg->frc_setting.iris_osd0_tl & 0xfff; + temp0 = (temp0*frc_setting->memc_hres)/frc_setting->disp_hres; + temp1 = (pcfg->frc_setting.iris_osd0_tl >> 16) & 0xfff; + temp1 = (temp1*frc_setting->memc_vres)/frc_setting->disp_vres; + + temp2 = pcfg->frc_setting.iris_osd0_br & 0xfff; + temp2 = (temp2*frc_setting->memc_hres)/frc_setting->disp_hres; + temp3 = (pcfg->frc_setting.iris_osd0_br >> 16) & 0xfff; + temp3 = (temp3*frc_setting->memc_vres)/frc_setting->disp_vres; + osd0_tl = (temp1 << 16) | temp0; + osd0_br = (temp3 << 16) | temp2; + //osd window 1 + temp0 = pcfg->frc_setting.iris_osd1_tl & 0xfff; + temp0 = (temp0*frc_setting->memc_hres)/frc_setting->disp_hres; + temp1 = (pcfg->frc_setting.iris_osd1_tl >> 16) & 0xfff; + temp1 = (temp1*frc_setting->memc_vres)/frc_setting->disp_vres; + + temp2 = pcfg->frc_setting.iris_osd1_br & 0xfff; + temp2 = (temp2*frc_setting->memc_hres)/frc_setting->disp_hres; + temp3 = (pcfg->frc_setting.iris_osd1_br >> 16) & 0xfff; + temp3 = (temp3*frc_setting->memc_vres)/frc_setting->disp_vres; + osd1_tl = (temp1 << 16) | temp0; + osd1_br = (temp3 << 16) | temp2; + //osd window 2 + temp0 = pcfg->frc_setting.iris_osd2_tl & 0xfff; + temp0 = (temp0*frc_setting->memc_hres)/frc_setting->disp_hres; + temp1 = (pcfg->frc_setting.iris_osd2_tl >> 16) & 0xfff; + temp1 = (temp1*frc_setting->memc_vres)/frc_setting->disp_vres; + + temp2 = pcfg->frc_setting.iris_osd2_br & 0xfff; + temp2 = (temp2*frc_setting->memc_hres)/frc_setting->disp_hres; + temp3 = (pcfg->frc_setting.iris_osd2_br >> 16) & 0xfff; + temp3 = (temp3*frc_setting->memc_vres)/frc_setting->disp_vres; + osd2_tl = (temp1 << 16) | temp0; + osd2_br = (temp3 << 16) | temp2; + //osd window 3 + temp0 = pcfg->frc_setting.iris_osd3_tl & 0xfff; + temp0 = (temp0*frc_setting->memc_hres)/frc_setting->disp_hres; + temp1 = (pcfg->frc_setting.iris_osd3_tl >> 16) & 0xfff; + temp1 = (temp1*frc_setting->memc_vres)/frc_setting->disp_vres; + + temp2 = pcfg->frc_setting.iris_osd3_br & 0xfff; + temp2 = (temp2*frc_setting->memc_hres)/frc_setting->disp_hres; + temp3 = (pcfg->frc_setting.iris_osd3_br >> 16) & 0xfff; + temp3 = (temp3*frc_setting->memc_vres)/frc_setting->disp_vres; + osd3_tl = (temp1 << 16) | temp0; + osd3_br = (temp3 << 16) | temp2; + //osd window 4 + temp0 = pcfg->frc_setting.iris_osd4_tl & 0xfff; + temp0 = (temp0*frc_setting->memc_hres)/frc_setting->disp_hres; + temp1 = (pcfg->frc_setting.iris_osd4_tl >> 16) & 0xfff; + temp1 = (temp1*frc_setting->memc_vres)/frc_setting->disp_vres; + + temp2 = pcfg->frc_setting.iris_osd4_br & 0xfff; + temp2 = (temp2*frc_setting->memc_hres)/frc_setting->disp_hres; + temp3 = (pcfg->frc_setting.iris_osd4_br >> 16) & 0xfff; + temp3 = (temp3*frc_setting->memc_vres)/frc_setting->disp_vres; + osd4_tl = (temp1 << 16) | temp0; + osd4_br = (temp3 << 16) | temp2; + + IRIS_LOGD("%s, input osd protect area: osd0_tl = 0x%x, osd0_br = 0x%x, osd1_tl = 0x%x, osd1_br = 0x%x, osd2_tl = 0x%x, osd2_br = 0x%x", __func__, + pcfg->frc_setting.iris_osd0_tl, pcfg->frc_setting.iris_osd0_br, + pcfg->frc_setting.iris_osd1_tl, pcfg->frc_setting.iris_osd1_br, + pcfg->frc_setting.iris_osd2_tl, pcfg->frc_setting.iris_osd2_br); + IRIS_LOGD("%s, input osd protect area: osd3_tl = 0x%x, osd3_br = 0x%x, osd4_tl = 0x%x, osd4_br = 0x%x", __func__, + pcfg->frc_setting.iris_osd3_tl, pcfg->frc_setting.iris_osd3_br, + pcfg->frc_setting.iris_osd4_tl, pcfg->frc_setting.iris_osd4_br); + IRIS_LOGD("%s, real osd protect area: osd0_tl = 0x%x, osd0_br = 0x%x, osd1_tl = 0x%x, osd1_br = 0x%x, osd2_tl = 0x%x, osd2_br = 0x%x", __func__, + osd0_tl, osd0_br, + osd1_tl, osd1_br, + osd2_tl, osd2_br); + IRIS_LOGD("%s, real osd protect area: osd3_tl = 0x%x, osd3_br = 0x%x, osd4_tl = 0x%x, osd4_br = 0x%x", __func__, + osd3_tl, osd3_br, + osd4_tl, osd4_br); + IRIS_LOGD("%s, osd window ctrl: = 0x%x, iris_osd_win_dynCompensate = 0x%x", __func__, + pcfg->frc_setting.iris_osd_window_ctrl, pcfg->frc_setting.iris_osd_win_dynCompensate); + + if (pcfg->frc_setting.iris_osd_window_ctrl & 0x1249) { //osd protection + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD0_TL, osd0_tl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD0_BR, osd0_br, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD1_TL, osd1_tl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD1_BR, osd1_br, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD2_TL, osd2_tl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD2_BR, osd2_br, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD3_TL, osd3_tl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD3_BR, osd3_br, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD4_TL, osd4_tl, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD4_BR, osd4_br, 0); + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD_WINDOW_CTRL, pcfg->frc_setting.iris_osd_window_ctrl, 0); + //iris_frc_reg_add(IRIS_PROXY_MB0, pcfg->frc_setting.iris_osd_win_dynCompensate, 0); + } else { + iris_frc_reg_add(IRIS_FI_ADDR + FI_OSD_WINDOW_CTRL, 0x00000000, 0); + } +} +int iris_mode_switch_update(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 mode = pcfg->switch_mode; + + if (pcfg->abypss_ctrl.abypass_mode == ANALOG_BYPASS_MODE) { + IRIS_LOGD("under abyp: switch_mode: %d", pcfg->switch_mode); + return IRIS_MODE_BYPASS; + } + + if (mode == IRIS_MODE_FRC_PREPARE) + mode = IRIS_MODE_FRC_PREPARE_DONE; + else if (mode == IRIS_MODE_RFB_PREPARE) + mode = IRIS_MODE_RFB_PREPARE_DONE; + else if (mode == IRIS_MODE_PT_PREPARE || mode == IRIS_MODE_PTLOW_PREPARE) + mode = IRIS_MODE_PT_PREPARE_DONE; + else if (mode == IRIS_MODE_RFB2FRC) + if (pcfg->rx_mode == 1) { // command mode + mode = iris_get_mode(); + if (mode != IRIS_MODE_FRC) + mode = pcfg->switch_mode; // keep original + } else + mode = IRIS_MODE_FRC; + else if (mode == IRIS_MODE_FRC2RFB) { + if (pcfg->rx_mode == 1) { // command mode + mode = iris_get_mode(); + if (mode == IRIS_MODE_RFB || mode == IRIS_MODE_PT) + mode = IRIS_MODE_RFB; + else + mode = pcfg->switch_mode; // keep original + } else + mode = IRIS_MODE_RFB; + } else if (mode == IRIS_MODE_RFB2PT) + mode = IRIS_MODE_PT; + else if (mode == IRIS_MODE_PT2RFB) + mode = IRIS_MODE_RFB; + else if (mode == IRIS_MODE_PT2BYPASS) + mode = IRIS_MODE_BYPASS; + else if (mode == IRIS_MODE_BYPASS2PT) + mode = IRIS_MODE_PT; + else if (mode == IRIS_MODE_FRC_CANCEL) + mode = IRIS_MODE_RFB; + pcfg->switch_mode = mode; + return mode; +} + +void iris_set_video_frame_rate_ms(u32 framerate) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + pcfg->frc_setting.in_fps = framerate/1000; +} + +void iris_set_out_frame_rate(u32 framerate) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGI("%s, default out framerate: %u, set framerate: %u", + __func__, pcfg->frc_setting.out_fps, framerate); + + //if (pcfg->frc_setting.default_out_fps == HIGH_FREQ) { + // //TODO: always set vtotal or not? + //if ((pcfg->frc_setting.out_fps != framerate) && + // (framerate == HIGH_FREQ || framerate == LOW_FREQ)) { + pcfg->frc_setting.out_fps = framerate; + + //IRIS_LOGI("%s, change framerate to: %d", __func__, framerate); + iris_dtg_frame_rate_set(framerate); + //} + //} + pcfg->cur_fps_in_iris = framerate; +} + +void iris_set_frc_var_display(int var_disp) +{ + iris_frc_var_disp = var_disp; +} + +void iris_set_ap_te(u8 ap_te) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (ap_te > pcfg->panel_te) { + IRIS_LOGI("%s, ap_te[%d] > panel_te[%d]", __func__, ap_te, pcfg->panel_te); + ap_te = pcfg->panel_te; + } + + if (ap_te != pcfg->ap_te) { + pcfg->ap_te = ap_te; + iris_frc_cmd_payload_init(); + iris_dtg_te_n2m_mode(0); + iris_frc_cmd_payload_release(); + } +} + +bool iris_update_vfr(struct iris_cfg *pcfg, bool enable) +{ + u32 frcc_pref_ctrl = pcfg->frc_setting.frcc_pref_ctrl; + static u32 write_data[2]; + + if (!mutex_trylock(&pcfg->panel->panel_lock)) { + IRIS_LOGI("%s:%d panel_lock is locked!", __func__, __LINE__); + mutex_lock(&pcfg->panel->panel_lock); + } + if (!pcfg->dynamic_vfr) { + mutex_unlock(&pcfg->panel->panel_lock); + IRIS_LOGI("dynamic_vfr is disable, return"); + return false; + } + + if (iris_frc_var_disp) { + if (enable) + frcc_pref_ctrl |= 0x2; + else + frcc_pref_ctrl &= ~0x2; + if (frcc_pref_ctrl == pcfg->frc_setting.frcc_pref_ctrl) { + mutex_unlock(&pcfg->panel->panel_lock); + IRIS_LOGI("same frcc_pref_ctrl value, return"); + return false; + } + pcfg->frc_setting.frcc_pref_ctrl = frcc_pref_ctrl; + write_data[0] = IRIS_FRC_MIF_ADDR + FRCC_PERF_CTRL; + write_data[1] = frcc_pref_ctrl; + iris_ocp_write_mult_vals(2, write_data); + } + mutex_unlock(&pcfg->panel->panel_lock); + return true; +} + +void iris_update_frc_fps(u8 iris_fps) +{ + iris_get_cfg()->frc_setting.out_fps = iris_fps; +} + +void iris_set_pwil_disp_ctrl(void) +{ + u32 write_data[4]; + uint32_t disp_ctrl0 = iris_pwil_disp_ctrl0(); + + write_data[0] = IRIS_PWIL_ADDR + PWIL_DISP_CTRL0; + write_data[1] = IRIS_PWIL_ADDR + disp_ctrl0; + write_data[2] = IRIS_PWIL_ADDR + PWIL_REG_UPDATE; + write_data[3] = 0x300; + + iris_ocp_write_mult_vals(4, write_data); +} + +int iris_dbgfs_ms_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + + debugfs_create_u32("frc_label", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_label); + + debugfs_create_u32("frc_var_disp_dual", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_var_disp_dual); + debugfs_create_u32("frc_var_disp", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_var_disp_dbg); + + debugfs_create_u32("frc_mnt_level", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_mnt_level); + debugfs_create_u32("frc_dynamic_off", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_dynamic_off); + + debugfs_create_u32("frc_pt_switch_on", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_pt_switch_on_dbg); + + debugfs_create_u32("mcu_enable", 0644, pcfg->dbg_root, + (u32 *)&iris_mcu_enable); + debugfs_create_u32("mcu_stop_check", 0644, pcfg->dbg_root, + (u32 *)&iris_mcu_stop_check); + debugfs_create_u32("frc_dma_disable", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_dma_disable); + debugfs_create_u32("dsi_write", 0644, pcfg->dbg_root, + (u32 *)&iris_w_path_select); + debugfs_create_u32("dsi_read", 0644, pcfg->dbg_root, + (u32 *)&iris_r_path_select); + debugfs_create_u32("frc_demo_window", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_demo_window); + debugfs_create_u32("dport_output_toggle", 0644, pcfg->dbg_root, + (u32 *)&iris_dport_output_toggle); + debugfs_create_u32("frc_fallback_disable", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_fallback_disable); + debugfs_create_u32("dynamic_sadgain_mid", 0644, pcfg->dbg_root, + (u32 *)&iris_dynamic_sadgain_mid); + debugfs_create_u32("dynamic_sadcore_mid", 0644, pcfg->dbg_root, + (u32 *)&iris_dynamic_sadcore_mid); + debugfs_create_u32("dynamic_outgain_mid", 0644, pcfg->dbg_root, + (u32 *)&iris_dynamic_outgain_mid); + debugfs_create_u32("dynamic_outcore_mid", 0644, pcfg->dbg_root, + (u32 *)&iris_dynamic_outcore_mid); + debugfs_create_u32("frc_osd_protection", 0644, pcfg->dbg_root, + (u32 *)&iris_frc_osd_protection); + debugfs_create_u32("mvc_tuning", 0644, pcfg->dbg_root, + (u32 *)&iris_mvc_tuning); + debugfs_create_u32("mtnsw_low_th", 0644, pcfg->dbg_root, + (u32 *)&iris_mtnsw_low_th); + debugfs_create_u32("mtnsw_high_th", 0644, pcfg->dbg_root, + (u32 *)&iris_mtnsw_high_th); + debugfs_create_u32("frcpt_switch_th", 0644, pcfg->dbg_root, + (u32 *)&iris_frcpt_switch_th); + debugfs_create_u32("te_dly_frc", 0644, pcfg->dbg_root, + (u32 *)&iris_te_dly_frc); + debugfs_create_u32("display_vtotal", 0644, pcfg->dbg_root, + (u32 *)&iris_display_vtotal); + return 0; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.h b/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.h new file mode 100755 index 000000000000..373865dfaef6 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_mode_switch.h @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +#ifndef MDSS_DSI_IRIS_MODE_SWITCH +#define MDSS_DSI_IRIS_MODE_SWITCH + +#define GRCP_HEADER 4 + +#define CEILING(x, y) (((x)+((y)-1))/(y)) + +#define IRIS_FRC_MIF_ADDR 0xf2020000 +#define IRIS_GMD_ADDR 0xf20a0000 +#define IRIS_FBD_ADDR 0xf20c0000 +#define IRIS_CAD_ADDR 0xf20e0000 +#define IRIS_MVC_ADDR 0xf2100000 +#define IRIS_FI_ADDR 0xf2160000 +#define IRIS_PWIL_ADDR 0xf1240000 +#define IRIS_PSR_ADDR 0xf1400000 +#define IRIS_SRAM_CTRL_ADDR 0xf1040000 +#define IRIS_SCALER_IN_ADDR 0xf1a20000 +#define IRIS_SCALER_PP_ADDR 0xf1a40000 +#define IRIS_BLENDING_ADDR 0xf1540000 +#define IRIS_CM_ADDR 0xf1560000 +#define IRIS_DTG_ADDR 0xf1200000 +#define IRIS_SYS_ADDR 0xf0000000 + +/*FRC_MIF*/ +#define FRCC_CTRL_REG0 0x10000 +#define FRCC_CTRL_REG1 0x10004 +#define FRCC_CTRL_REG2 0x10008 +#define FRCC_CTRL_REG3 0x1000c +#define FRCC_CTRL_REG4 0x10010 +#define FRCC_CTRL_REG5 0x10014 +#define FRCC_CTRL_REG6 0x10018 +#define FRCC_CTRL_REG7 0x1001c +#define FRCC_CTRL_REG8 0x10020 +#define FRCC_CTRL_REG9 0x10024 +#define FRCC_CTRL_REG10 0x10028 +#define FRCC_CTRL_REG11 0x1002c +#define FRCC_CTRL_REG12 0x10030 +#define FRCC_CTRL_REG13 0x10034 +#define FRCC_CTRL_REG14 0x10038 +#define FRCC_CTRL_REG15 0x1003c +#define FRCC_CTRL_REG16 0x10040 +#define FRCC_CTRL_REG17 0x10044 +#define FRCC_CTRL_REG18 0x10048 +#define FRCC_CMD_MOD_TH 0x1004c +#define FRCC_DTG_SYNC 0x10060 +#define FRCC_SWITCH_CTRL 0x10074 +#define FRCC_SWFBK_CTRL 0x10078 +#define FRCC_01PHASE_CTRL0 0x1007c +#define FRCC_01PHASE_CTRL1 0x10080 +#define FRCC_TEOFFSET_CTRL 0x10090 +#define FRCC_PERF_CTRL 0x10094 +#define FRCC_TEOFFSET_ADJ 0x10098 +#define FRCC_TEADJ_TH 0x1009c +#define FRCC_MNTSWITCH_TH 0x100a0 +#define FRCC_EXT_MOTION 0x100a4 +#define FRCC_EXT_TE_OFFSET 0x100a8 +#define FRCC_PHASELUT_CLIP 0x100ac +#define FRCC_RW_PROT_TH 0x100b0 +#define FRCC_REC_META_CTRL 0x100b4 +#define FRCC_METAGEN3 0x100b8 +#define FRCC_FRCPT_SWITCH_CTRL 0x100c0 +#define FRCC_REG_SHDW 0x11198 +#define IMIF_MODE_CTRL 0x12000 +#define IMIF_DW_PER_LINE 0x12008 +#define IMIF_VSIZE 0x1200c +#define IMIF_SW_UPDATE_EN 0x13400 +#define MMIF_CTRL1 0x14000 +#define MMIF_CTRL2 0x14004 +#define MMIF_PHASE1_BA 0x140f0 +#define MMIF_PHASE0_BA 0x140f4 +#define MMIF_UPDATE 0x15020 +#define FMIF_CTRL 0x16000 +#define FMIF_VD_FRM_ATTRIBUTE0 0x16004 +#define FMIF_VD_FRM_ATTRIBUTE1 0x16008 +#define FMIF_MV_FRM_ATTRIBUTE0 0x16014 +#define FMIF_MV_FRM_ATTRIBUTE1 0x16020 +#define FMIF_REG_SHDW 0x17000 + +/* GMD */ +#define GMD_GAIN 0x00000 +#define GMD_FILT 0x00004 +#define GMD_ACCUM 0x00008 +#define GMD_SHIFT 0x0000c +#define GMD_START 0x00010 +#define GMD_STOP 0x00014 +#define GMD_CTRL 0x00020 + +/* FBD */ +#define FILMBD_RESOLUTION 0x00018 +#define FILMBD_WIN_STOP_SET 0x00020 +#define FILMBD_TOP_CTRL 0x00024 + +/* CAD */ +#define NEW_FRM_FLG_DET_1 0x00004 +#define CAD_DET_BASIC_CAD 0x0000c +#define CAD_DET_STVT 0x00010 +#define CAD_DET_BAD_EDIT 0x00014 +#define CAD_DET_VOF_0 0x00018 +#define COMMON 0x00030 +#define DUMMY 0x00040 +#define SW_DONE 0x1ffd4 + +/* MVC */ +#define MVC_CTRL_0 0x00000 +#define MVC_TOP_CTRL_0 0x0000c +#define GLB_MVSELECT_1 0x00080 +#define GLB_MVSELECT_2 0x00084 +#define HALORED_2 0x00094 +#define MVC_OSDDET_0 0x000b8 +#define MVC_OSDDET_1 0x000bc +#define MVC_POSTFILT_1 0x000dc +#define MVC_POSTGLBDC_0 0x00118 +#define MVC_SAD_2 0x00180 +#define HISTMV_CTRL_1 0x00190 +#define HISTMV_CTRL_2 0x00194 +#define HISTMV_CTRL_3 0x00198 +#define HISTMV_CTRL_4 0x0019c +#define HISTMV_STEP 0x001a0 +#define HISTMV_BASE 0x001a4 +#define HLMD_CTRL 0x001d4 +#define MVC_SW_UPDATE 0x1ff00 + +/* FI */ +#define FI_CLOCK_GATING 0x0000c +#define FI_RANGE_CTRL 0x00014 +#define FI_DEMO_COL_SIZE 0x00018 +#define FI_DEMO_MODE_CTRL 0x0001c +#define FI_DEMO_MODE_RING 0x00020 +#define FI_DEMO_ROW_SIZE 0x00024 +#define FI_OSD0_TL 0x00038 +#define FI_OSD1_TL 0x0003c +#define FI_OSD2_TL 0x00040 +#define FI_OSD3_TL 0x00044 +#define FI_OSD4_TL 0x00048 +#define FI_OSD0_BR 0x0004c +#define FI_OSD1_BR 0x00050 +#define FI_OSD2_BR 0x00054 +#define FI_OSD3_BR 0x00058 +#define FI_OSD4_BR 0x0005c +#define FI_OSD_WINDOW_CTRL 0x00060 +#define FI_VIDEO_BUF_CTRL 0x00064 +#define FI_V9_GENERIC_CTRL 0x00078 +#define FI_MISC_CTRL 0x0007c +#define FI_CSC_CTRL 0x00100 +#define FI_CSC_COEF0 0x00104 +#define FI_CSC_COEF1 0x00108 +#define FI_CSC_COEF2 0x0010c +#define FI_CSC_COEF3 0x00110 +#define FI_CSC_COEF4 0x00114 +#define FI_CSC_OFFSET0 0x00118 +#define FI_CSC_OFFSET1 0x0011c +#define FI_CSC_OFFSET2 0x00120 +#define FI_SHDW_CTRL 0x1ff00 + +/* PWIL */ +#define PWIL_CTRL 0x00000 +#define PWIL_CTRL1 0x00004 +#define DATA_PATH_CTRL 0x00008 +#define DATA_PATH_CTRL1 0x0000c +#define PWIL_STATUS 0x00030 +#define PWIL_VIDEO_CTRL0 0x01028 +#define PWIL_VIDEO_CTRL1 0x0102c +#define PWIL_VIDEO_CTRL2 0x01030 +#define PWIL_VIDEO_CTRL3 0x01034 +#define PWIL_VIDEO_CTRL4 0x01038 +#define PWIL_VIDEO_CTRL5 0x0103c +#define PWIL_VIDEO_CTRL6 0x01040 +#define PWIL_VIDEO_CTRL7 0x01044 +#define PWIL_VIDEO_CTRL8 0x01048 +#define PWIL_VIDEO_CTRL11 0x0104c +#define PWIL_VIDEO_CTRL12 0x01050 +#define PWIL_CSC_CTRL 0x00078 +#define PWIL_CSC_COEF0 0x0007c +#define PWIL_CSC_COEF1 0x00080 +#define PWIL_CSC_COEF2 0x00084 +#define PWIL_CSC_COEF3 0x00088 +#define PWIL_CSC_COEF4 0x0008c +#define PWIL_CSC_OFFSET0 0x00090 +#define PWIL_CSC_OFFSET1 0x00094 +#define PWIL_CSC_OFFSET2 0x00098 +#define PWIL_PIAD_FRC_INFO 0x00108 +#define PWIL_DISP_CTRL0 0x010b0 +#define PWIL_FBO_CTRL 0x010c8 +#define PWIL_CMD_CTRL0 0x010f0 +#define PWIL_CMD_CTRL1 0x010f4 +#define PWIL_DPCD_CTRL 0x000c4 +#define PWIL_REG_UPDATE 0x10000 + +/* PSR_MIF */ +#define PSR_MIF_CTRL 0x00000 +#define PSR_ELFIFO_CTRL 0x00004 +#define PSR_RW_CTRL 0x00010 +#define PSR_ELFIFO_STRIDE 0x0002c +#define PSR_WR_FIFO_DEPTH1 0x00054 +#define PSR_SLICE_RAW_HSIZE 0x00104 +#define PSR_SLICE_SIZE0 0x0010c +#define PSR_SLICE_SIZE1 0x00110 +#define PSR_SLICE_SIZE2 0x00114 +#define PSR_SLICE_SIZE3 0x00118 +#define PSR_SW_CONTROL 0x1ff00 + +/* SRAM_CTRL */ +#define RAMCTRL_PWRCTRL 0x00000 + +/* SCALER */ +#define SCALER_TOP_CTRL 0x00000 +#define VS_CTRL 0x00004 +#define VS_VINC_0 0x00008 +#define VS_VINC_1 0x0000c +#define VS_ALGPARM 0x00010 +#define VS_ALGPARM_MAXLINE 0x00014 +#define VS_OFFSET_0 0x00018 +#define VS_OFFSET_1 0x0001c +#define VS_BGR 0x00020 +#define HS_CTRL 0x00024 +#define HS_PIXELBOUNDARY 0x00028 +#define HS_HINC_0 0x0002c +#define HS_HINC_1 0x00030 +#define HS_OFFSET_0 0x00034 +#define HS_OFFSET_1 0x00038 +#define HS_ALGPARM 0x0003c +#define HS_BGR 0x00040 +#define SCALE_V3_GENERIC_CTRL 0x00044 + + +/* BLENDING */ +#define BLENDING_CTRL 0x00000 +#define BLENDING_VIDEO_CTRL 0x00030 + +/* CM */ +#define CM_CNTL_1 0x00004 + +/* DTG */ +#define DTG_REG_8 0x00020 +#define DTG_REG_9 0x00024 +#define DTG_REG_10 0x00028 +#define DTG_REG_11 0x0002c +#define DTG_REG_12 0x00030 +#define DTG_REG_14 0x00038 +#define DTG_REG_19 0x0004c +#define DTG_REG_23 0x0005c +#define DTG_REG_26 0x00068 +#define DTG_REG_27 0x0006c +#define DTG_REG_41 0x000A4 +#define DTG_REG_45 0x000B4 +#define DTG_UPDATE 0x10000 + +#define MCU_SW_RESET 0x000c8 +#define IRIS_PROXY_MB0 0xf0040000 +#define IRIS_PROXY_MB1 0xf0040008 +#define IRIS_PROXY_MB5 0xf0040028 +#define IRIS_MCU_INFO_1 0xf0fe0000 +#define IRIS_MCU_INFO_2 0xf0fe0004 +#define IRIS_UNIT_CTRL_INTEN 0xf0060008 +#define IRIS_TX_RESERVE_0 0xf1880038 +#define IRIS_DPORT_CTRL0 0xf1220000 +#define IRIS_DPORT_REGSEL 0xf1220064 + +struct iris_grcp_cmd { + char cmd[CMD_PKT_SIZE]; + int cmd_len; +}; + +enum iris_frc_lut { + IRIS_FRC_PHASE_TALBE_V1, + IRIS_FRC_PHASE_TABLE_V2_12to60, + IRIS_FRC_PHASE_TABLE_V2_12to90, + IRIS_FRC_PHASE_TABLE_V2_12to120, + IRIS_FRC_PHASE_TABLE_V2_15to60, + IRIS_FRC_PHASE_TABLE_V2_15to90, + IRIS_FRC_PHASE_TABLE_V2_15to120, + IRIS_FRC_PHASE_TABLE_V2_24to60, + IRIS_FRC_PHASE_TABLE_V2_24to90, + IRIS_FRC_PHASE_TABLE_V2_24to120, + IRIS_FRC_PHASE_TABLE_V2_25to60, + IRIS_FRC_PHASE_TABLE_V2_25to90, + IRIS_FRC_PHASE_TABLE_V2_25to120, + IRIS_FRC_PHASE_TABLE_V2_30to60, + IRIS_FRC_PHASE_TABLE_V2_30to90, + IRIS_FRC_PHASE_TABLE_V2_30to120, + IRIS_FRC_PHASE_TABLE_V2_60to90, + IRIS_FRC_PHASE_TABLE_V2_60to120 +}; + +void iris_mode_switch_proc(u32 mode); +void iris_set_video_frame_rate_ms(u32 framerate); +void iris_set_out_frame_rate(u32 framerate); +void iris_set_frc_var_display(int var_disp); +int iris_mode_switch_update(void); +int iris_dbgfs_ms_init(struct dsi_display *display); +void iris_set_ap_te(u8 ap_te); +bool iris_update_vfr(struct iris_cfg *pcfg, bool enable); +int32_t iris_fi_osd_protect_window(u32 Top_left_position, u32 bottom_right_position, u32 osd_window_ctrl, u32 Enable, u32 DynCompensate); +void iris_fi_demo_window(u32 DemoWinMode); +void iris_fi_demo_window_cal(void); +void iris_update_frc_fps(u8 iris_fps); +void iris_set_pwil_disp_ctrl(void); +#endif + diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_pq.c b/techpack/display/msm/dsi/iris/dsi_iris5_pq.c new file mode 100755 index 000000000000..d3dcf8f55aab --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_pq.c @@ -0,0 +1,3031 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <video/mipi_display.h> +#include <sde_encoder_phys.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_pq.h" +#include "dsi_iris5_ioctl.h" +#include "dsi_iris5_log.h" + + +extern uint8_t iris_pq_update_path; + +static bool iris_require_yuv_input; +static bool iris_HDR10; +static bool iris_HDR10_YCoCg; +static bool shadow_iris_require_yuv_input; +static bool shadow_iris_HDR10; +static bool shadow_iris_HDR10_YCoCg; +static bool iris_yuv_datapath; +static bool iris_capture_ctrl_en; +static bool iris_debug_cap; +static u8 iris_dbc_lut_index; +static u8 iris_sdr2hdr_mode; +static struct iris_setting_info iris_setting; +static bool iris_skip_dma; +extern int iris_frc_dma_disable; +static u32 iris_min_color_temp; +static u32 iris_max_color_temp; +static u32 iris_min_x_value; +static u32 iris_max_x_value; +static u32 iris_sdr2hdr_lut2ctl = 0xFFE00000; +static u32 iris_sdr2hdr_lutyctl = 0xFFFF0000; + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#define IRIS_CCT_MIN_VALUE 2500 +#define IRIS_CCT_MAX_VALUE 7500 +#define IRIS_CCT_STEP 25 +#define IRIS_X_6500K 3128 +#define IRIS_X_7500K 2991 +#define IRIS_X_7700K 2969 +#define IRIS_X_2500K 4637 +#define IRIS_LAST_BIT_CTRL 1 + +/*range is 2500~10000*/ +static u32 iris_color_x_buf[] = { + 4637, 4626, 4615, 4603, + 4591, 4578, 4565, 4552, + 4538, 4524, 4510, 4496, + 4481, 4467, 4452, 4437, + 4422, 4407, 4392, 4377, + 4362, 4347, 4332, 4317, + 4302, 4287, 4272, 4257, + 4243, 4228, 4213, 4199, + 4184, 4170, 4156, 4141, + 4127, 4113, 4099, 4086, + 4072, 4058, 4045, 4032, + 4018, 4005, 3992, 3980, + 3967, 3954, 3942, 3929, + 3917, 3905, 3893, 3881, + 3869, 3858, 3846, 3835, + 3823, 3812, 3801, 3790, + 3779, 3769, 3758, 3748, + 3737, 3727, 3717, 3707, + 3697, 3687, 3677, 3668, + 3658, 3649, 3639, 3630, + 3621, 3612, 3603, 3594, + 3585, 3577, 3568, 3560, + 3551, 3543, 3535, 3527, + 3519, 3511, 3503, 3495, + 3487, 3480, 3472, 3465, + 3457, 3450, 3443, 3436, + 3429, 3422, 3415, 3408, + 3401, 3394, 3388, 3381, + 3375, 3368, 3362, 3356, + 3349, 3343, 3337, 3331, + 3325, 3319, 3313, 3307, + 3302, 3296, 3290, 3285, + 3279, 3274, 3268, 3263, + 3258, 3252, 3247, 3242, + 3237, 3232, 3227, 3222, + 3217, 3212, 3207, 3202, + 3198, 3193, 3188, 3184, + 3179, 3175, 3170, 3166, + 3161, 3157, 3153, 3149, + 3144, 3140, 3136, 3132, + 3128, 3124, 3120, 3116, + 3112, 3108, 3104, 3100, + 3097, 3093, 3089, 3085, + 3082, 3078, 3074, 3071, + 3067, 3064, 3060, 3057, + 3054, 3050, 3047, 3043, + 3040, 3037, 3034, 3030, + 3027, 3024, 3021, 3018, + 3015, 3012, 3009, 3006, + 3003, 3000, 2997, 2994, + 2991, 2988, 2985, 2982, + 2980, 2977, 2974, 2971, + 2969, 2966, 2963, 2961, + 2958, 2955, 2953, 2950, + 2948, 2945, 2943, 2940, + 2938, 2935, 2933, 2930, + 2928, 2926, 2923, 2921, + 2919, 2916, 2914, 2912, + 2910, 2907, 2905, 2903, + 2901, 2899, 2896, 2894, + 2892, 2890, 2888, 2886, + 2884, 2882, 2880, 2878, + 2876, 2874, 2872, 2870, + 2868, 2866, 2864, 2862, + 2860, 2858, 2856, 2854, + 2853, 2851, 2849, 2847, + 2845, 2844, 2842, 2840, + 2838, 2837, 2835, 2833, + 2831, 2830, 2828, 2826, + 2825, 2823, 2821, 2820, + 2818, 2817, 2815, 2813, + 2812, 2810, 2809, 2807, + 2806, 2804, 2803, 2801, + 2800, 2798, 2797, 2795, + 2794, 2792, 2791, 2789, + 2788, +}; + +/*G0,G1,G2,G3,G4,G5*/ +static u32 m_dwGLuxBuffer[] = {210, 1024, 1096, 1600, 2000, 2400}; +/*K0,K1,K2,K3,K4,K5*/ +static u32 m_dwKLuxBuffer[] = {511, 51, 46, 30, 30, 30}; +/*X1,X2,X3,X4,X5*/ +static u32 m_dwXLuxBuffer[] = {20, 1200, 1300, 1536, 3584}; +/*org=320; Joey modify 20160712*/ +static u32 m_dwBLux = 50; +/*org=128; Joey modify 20160712*/ +static u32 m_dwTH_LuxAdj = 150; + +typedef enum { + eScalerDownNom = 0, + eScalerDown1_6, //shrink ratio >=1.6; + eScalerDown1_8, //shrink ratio >=1.8; + eScalerDown2_0, //shrink ratio >=2; + eScalerDown2_2, + eScalerDown2_4, + eScalerDown2_6, + eScalerDown2_8, + eScaleDownInvalid, +} eScalerDownSoftRatio; + +u8 iris_get_dbc_lut_index(void) +{ + return iris_dbc_lut_index; +} + +struct iris_setting_info *iris_get_setting(void) +{ + return &iris_setting; +} + +void iris_set_yuv_input(bool val) +{ + shadow_iris_require_yuv_input = val; +} + +void iris_set_HDR10_YCoCg(bool val) +{ + shadow_iris_HDR10_YCoCg = val; +} + +void iris_set_sdr2hdr_mode(u8 val) +{ + iris_sdr2hdr_mode = val; +} + +int iris_get_hdr_enable(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + if (pcfg->valid < PARAM_PARSED) + return 0; + else if (iris_HDR10_YCoCg) + return 2; + else if (iris_HDR10) + return 1; + else if (iris_setting.quality_cur.pq_setting.sdr2hdr != SDR2HDR_Bypass) + return 100; + else + return 0; +} + +bool iris_dspp_dirty(void) +{ + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + + if (pqlt_cur_setting->dspp_dirty > 0) { + IRIS_LOGI("DSPP is dirty"); + pqlt_cur_setting->dspp_dirty--; + return true; + } + + return false; +} + +void iris_quality_setting_off(void) +{ + iris_setting.quality_cur.al_bl_ratio = 0; + if (iris_setting.quality_cur.pq_setting.sdr2hdr != SDR2HDR_Bypass) { + iris_setting.quality_cur.pq_setting.sdr2hdr = SDR2HDR_Bypass; + iris_sdr2hdr_level_set(SDR2HDR_Bypass); + iris_setting.quality_cur.pq_setting.cmcolorgamut = 0; + iris_cm_color_gamut_set( + iris_setting.quality_cur.pq_setting.cmcolorgamut); + } else { + iris_cm_color_gamut_pre_clear(); + } + + iris_capture_ctrl_en = false; + iris_skip_dma = false; + iris_sdr2hdr_mode = 0; +} + +bool iris_get_debug_cap(void) +{ + return iris_debug_cap; +} + +void iris_set_debug_cap(bool val) +{ + iris_debug_cap = val; +} + +void iris_set_skip_dma(bool skip) +{ + IRIS_LOGD("skip_dma=%d", skip); + iris_skip_dma = skip; +} + +static int iris_capture_disable_pq(struct iris_update_ipopt *popt, bool *skiplast) +{ + int len = 0; + + *skiplast = 0; + if ((!iris_capture_ctrl_en) && (!iris_debug_cap)) { + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x50, 0x50, IRIS_LAST_BIT_CTRL); + else + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x52, 0x52, IRIS_LAST_BIT_CTRL); + + *skiplast = 1; + } + if (!iris_dynamic_power_get() && !iris_skip_dma) + *skiplast = 1; + return len; +} + +static int iris_capture_enable_pq(struct iris_update_ipopt *popt, int oldlen) +{ + int len = oldlen; + + if ((!iris_capture_ctrl_en) && (!iris_debug_cap)) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x51, 0x51, + (!iris_dynamic_power_get()) ? 0x01 : 0x0); + + if (!iris_dynamic_power_get() && !iris_skip_dma) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + return len; +} + +static int iris_capture_disable_lce(struct iris_update_ipopt *popt, bool *skiplast) +{ + int len = 0; + + *skiplast = 0; + if ((!iris_capture_ctrl_en) + && (iris_lce_power_status_get()) + && (!iris_debug_cap)) { + if (!iris_dynamic_power_get()) + iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x50, 0x50, IRIS_LAST_BIT_CTRL); + else + iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x52, 0x52, IRIS_LAST_BIT_CTRL); + + *skiplast = 1; + } + if (!iris_dynamic_power_get() && !iris_skip_dma) + *skiplast = 1; + return len; +} + +static int iris_capture_enable_lce(struct iris_update_ipopt *popt, int oldlen) +{ + int len = oldlen; + + if ((!iris_capture_ctrl_en) + && (iris_lce_power_status_get()) + && (!iris_debug_cap)) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x51, 0x51, (!iris_dynamic_power_get())?0x01:0x0); + + if (!iris_dynamic_power_get() && !iris_skip_dma) { + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe3, 0xe3, 0x01); + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + } + return len; +} + +void iris_init_ipopt_ip(struct iris_update_ipopt *ipopt, int len) +{ + int i = 0; + + for (i = 0; i < len; i++) + ipopt[i].ip = 0xff; +} + +static u32 iris_color_temp_x_get(u32 index) +{ + return iris_color_x_buf[index]; +} + +void iris_scaler_filter_ratio_get(void) +{ + u32 dwRatioDiff = 0; + struct iris_cfg *pcfg = NULL; + eScalerDownSoftRatio dwScaleDownRatio = eScalerDownNom; + + pcfg = iris_get_cfg(); + dwRatioDiff = pcfg->frc_setting.disp_hres * 10 / pcfg->frc_setting.memc_hres; + + if ((dwRatioDiff < 20) && (dwRatioDiff >= 18)) + dwScaleDownRatio = eScalerDown1_8; + else if ((dwRatioDiff < 22) && (dwRatioDiff >= 20)) + dwScaleDownRatio = eScalerDown2_0; + else if ((dwRatioDiff < 24) && (dwRatioDiff >= 22)) + dwScaleDownRatio = eScalerDown2_2; + else if ((dwRatioDiff < 26) && (dwRatioDiff >= 24)) + dwScaleDownRatio = eScalerDown2_4; + else if ((dwRatioDiff < 28) && (dwRatioDiff >= 26)) + dwScaleDownRatio = eScalerDown2_6; + else if (dwRatioDiff >= 28) + dwScaleDownRatio = eScalerDown2_8; + + if (dwScaleDownRatio < eScalerDown1_6) + iris_scaler_filter_update(SCALER_PP, 0); + else + iris_scaler_filter_update(SCALER_PP, 1); + + IRIS_LOGI("%s, scaler ratio=%d", __func__, dwScaleDownRatio); + iris_scaler_filter_update(SCALER_INPUT, (u32)dwScaleDownRatio); +} + +void iris_pq_parameter_init(void) +{ + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + struct iris_cfg *pcfg = iris_get_cfg(); + u32 index; + + if (pqlt_cur_setting->pq_setting.sdr2hdr + == SDR2HDR_Bypass) + iris_yuv_datapath = false; + else + iris_yuv_datapath = true; + + /* no pxlw node */ + if (pcfg->valid <= PARAM_EMPTY) { + IRIS_LOGW("no pxlw node"); + return; + } + + iris_dbc_lut_index = 0; + if (pcfg->panel->panel_mode == DSI_OP_VIDEO_MODE) + iris_debug_cap = true; + + iris_min_color_temp = pcfg->min_color_temp; + iris_max_color_temp = pcfg->max_color_temp; + + index = (iris_min_color_temp-IRIS_CCT_MIN_VALUE)/IRIS_CCT_STEP; + iris_min_x_value = iris_color_temp_x_get(index); + + index = (iris_max_color_temp-IRIS_CCT_MIN_VALUE)/IRIS_CCT_STEP; + iris_max_x_value = iris_color_temp_x_get(index); + + pqlt_cur_setting->colortempvalue = 6500; + + IRIS_LOGI("%s, iris_min_x_value=%d, iris_max_x_value = %d", __func__, iris_min_x_value, iris_max_x_value); +} + +void iris_peaking_level_set(u32 level) +{ + u32 csc; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + csc = (level == 0) ? 0x11 : 0x10; + if (iris_yuv_datapath == true) + csc = 0x11; + + len = iris_capture_disable_pq(popt, &skiplast); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PEAKING, + level, 0x01); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PEAKING, + csc, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("peaking level=%d, len=%d", level, len); +} + +static int iris_cm_csc_para_set(struct iris_update_ipopt *popt, uint8_t skip_last, uint32_t csc_ip, uint32_t *csc_value) +{ + int32_t ip = 0; + int32_t opt_id = 0; + uint32_t *data = NULL; + uint32_t val = 0; + int len = 0; + struct iris_ip_opt *psopt; + + if (csc_value == NULL) { + IRIS_LOGE("csc value is empty"); + return 0; + } + + ip = csc_ip; + opt_id = 0x40; + psopt = iris_find_ip_opt(ip, opt_id); + if (psopt == NULL) { + IRIS_LOGE("can not find ip = %02x opt_id = %02x", ip, opt_id); + return 1; + } + + data = (uint32_t *)psopt->cmd[0].msg.tx_buf; + IRIS_LOGD("csc: csc0=0x%x, csc1=0x%x, csc2=0x%x, csc3=0x%x, csc4=0x%x", + csc_value[0], csc_value[1], csc_value[2], csc_value[3], csc_value[4]); + val = csc_value[0]; + val &= 0x7fff7fff; + data[3] = val; + val = csc_value[1]; + val &= 0x7fff7fff; + data[4] = val; + val = csc_value[2]; + val &= 0x7fff7fff; + data[5] = val; + val = csc_value[3]; + val &= 0x7fff7fff; + data[6] = val; + val = csc_value[4]; + val &= 0x00007fff; + data[7] = val; + + iris_send_ipopt_cmds(ip, opt_id); + + return len; +} + +void iris_cm_csc_level_set(u32 csc_ip, u32 *csc_value) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + len = iris_cm_csc_para_set(popt, skiplast, csc_ip, csc_value); + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("%s csc len=%d", (csc_ip == IRIS_IP_DPP) ? "dpp" : "cm", len); +} + +void iris_cm_6axis_level_set(u32 level) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + //bool cm_csc_enable = true; + //struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + //f ((level == 0) + // && (pqlt_cur_setting->pq_setting.cm6axis == 0) + // && (iris_yuv_datapath == false)) + // cm_csc_enable = false; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_CM, level, skiplast); + + //len = iris_cm_csc_set(popt, skiplast, cm_csc_enable); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("cm 6axis level=%d, len=%d", level, len); +} + +void iris_cm_ftc_enable_set(u32 level) +{ + u32 locallevel; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + locallevel = 0x10 | (u8)level; + len = iris_capture_disable_pq(popt, &skiplast); + + len = iris_update_ip_opt( + popt, IP_OPT_MAX, IRIS_IP_CM, locallevel, skiplast); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("cm ftc enable=%d, len=%d", level, len); +} + + +void iris_scurve_enable_set(u32 level) +{ + u32 locallevel; + u32 scurvelevel; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + u8 enable = 0; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + if (level > 0) { + enable = 1; + scurvelevel = (0x70 + (level - 1)); + len = iris_update_ip_opt( + popt, IP_OPT_MAX, IRIS_IP_DPP, scurvelevel, 0x01); + } + + locallevel = 0x50 | enable; + len = iris_update_ip_opt( + popt, IP_OPT_MAX, IRIS_IP_DPP, locallevel, skiplast); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("scurve level=%d, len=%d", level, len); +} + +int iris_cm_ratio_set(struct iris_update_ipopt *popt, uint8_t skip_last) +{ + u32 tablesel; + u32 index; + u32 xvalue; + u32 ratio; + u32 value; + u32 regvalue = 0; + struct iris_update_regval regval; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + int len; + + if (pqlt_cur_setting->pq_setting.cmcolortempmode == IRIS_COLOR_TEMP_MANUL) + value = pqlt_cur_setting->colortempvalue; + else if (pqlt_cur_setting->pq_setting.cmcolortempmode == IRIS_COLOR_TEMP_AUTO) + value = pqlt_cur_setting->cctvalue; + else + value = IRIS_CCT_MIN_VALUE; + + + if (value > iris_max_color_temp) + value = iris_max_color_temp; + else if (value < iris_min_color_temp) + value = iris_min_color_temp; + index = (value - IRIS_CCT_MIN_VALUE) / 25; + xvalue = iris_color_temp_x_get(index); + + if (xvalue == iris_min_x_value) { + tablesel = 0; + regvalue = tablesel | 0x02; + } else if ((xvalue < iris_min_x_value) && (xvalue >= IRIS_X_6500K)) { + tablesel = 0; + ratio = ((xvalue - IRIS_X_6500K) * 16383) / (iris_min_x_value - IRIS_X_6500K); + regvalue = tablesel | (ratio << 16); + } else if ((xvalue >= iris_max_x_value) && (xvalue < IRIS_X_6500K)) { + tablesel = 1; + ratio = ((xvalue - iris_max_x_value) * 16383) / (IRIS_X_6500K - iris_max_x_value); + regvalue = tablesel | (ratio << 16); + } + + regval.ip = IRIS_IP_DPP; + regval.opt_id = 0xfd; + regval.mask = 0x3fff0003; + regval.value = regvalue; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DPP, 0xfd, 0xfd, skip_last); + IRIS_LOGI("cm color temperature value=%d", value); + return len; +} + +u32 iris_cm_ratio_set_for_iic(void) +{ + u32 tablesel; + u32 index; + u32 xvalue; + u32 ratio; + u32 value; + u32 regvalue = 0; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + + value = pqlt_cur_setting->colortempvalue; + + if (value > iris_max_color_temp) + value = iris_max_color_temp; + else if (value < iris_min_color_temp) + value = iris_min_color_temp; + index = (value - IRIS_CCT_MIN_VALUE) / 25; + xvalue = iris_color_temp_x_get(index); + + if (xvalue == iris_min_x_value) { + tablesel = 0; + regvalue = tablesel | 0x02; + } else if ((xvalue < iris_min_x_value) && (xvalue >= IRIS_X_7700K)) { + tablesel = 0; + ratio = ((xvalue - IRIS_X_7700K) * 16383) / (iris_min_x_value - IRIS_X_7700K); + regvalue = tablesel | (ratio << 16); + } else if ((xvalue >= iris_max_x_value) && (xvalue < IRIS_X_7700K)) { + tablesel = 1; + ratio = ((xvalue - iris_max_x_value) * 16383) / (IRIS_X_7700K - iris_max_x_value); + regvalue = tablesel | (ratio << 16); + } + + IRIS_LOGD("cm color temperature value=%d", value); + + return regvalue; +} + +void iris_cm_colortemp_mode_set(u32 mode) +{ + struct iris_update_regval regval; + bool skiplast = 0; + int len = 0; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + + /*do not generate lut table during mode switch.*/ + if (pqlt_cur_setting->source_switch != 1) { + iris_init_ipopt_ip(popt, IP_OPT_MAX); + regval.ip = IRIS_IP_DPP; + regval.opt_id = 0xfc; + regval.mask = 0x00000031; + regval.value = (mode == 0)?0x00000020:0x00000011; + len = iris_capture_disable_pq(popt, &skiplast); + if (mode == IRIS_COLOR_TEMP_OFF) + iris_update_ip_opt(popt, IP_OPT_MAX, GAMMA_LUT, + 0x00, 0x01); + else + iris_update_ip_opt(popt, IP_OPT_MAX, GAMMA_LUT, + pqlt_cur_setting->pq_setting.cmcolorgamut + 0x01, 0x01); + + if (mode > IRIS_COLOR_TEMP_OFF) + len = iris_cm_ratio_set(popt, 0x01); + + if (pqlt_cur_setting->source_switch == 2) + pqlt_cur_setting->source_switch = 0; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DPP, + 0xfc, 0xfc, skiplast); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + } + IRIS_LOGI("cm color temperature mode=%d, len=%d", mode, len); +} + +void iris_cm_color_temp_set(void) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + /*struct quality_setting *pqlt_cur_setting = & iris_setting.quality_cur;*/ + + /*if(pqlt_cur_setting->pq_setting.cmcolorgamut == 0) {*/ + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + len = iris_cm_ratio_set(popt, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + /*}*/ + IRIS_LOGI("%s, len = %d", __func__, len); +} + +void iris_cm_color_gamut_pre_set(u32 source_switch) +{ + struct iris_update_regval regval; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + /*add protection for source and scene switch at the same time*/ + if (source_switch == 3) + source_switch = 1; + pqlt_cur_setting->source_switch = source_switch; + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + regval.ip = IRIS_IP_DPP; + regval.opt_id = 0xfc; + regval.mask = 0x00000011; + regval.value = 0x00000000; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DPP, + 0xfc, 0xfc, skiplast); + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("source switch = %d, len=%d", source_switch, len); +} + +void iris_cm_color_gamut_set(u32 level) +{ + struct iris_update_regval regval; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + u32 gammalevel; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + regval.ip = IRIS_IP_DPP; + regval.opt_id = 0xfc; + regval.mask = 0x00000011; + regval.value = 0x00000011; + + /*use liner gamma if cm lut disable*/ + if (pqlt_cur_setting->pq_setting.cmcolortempmode == + IRIS_COLOR_TEMP_OFF) + gammalevel = 0; + else + gammalevel = level + 1; + + + iris_update_ip_opt(popt, IP_OPT_MAX, GAMMA_LUT, gammalevel, 0x01); + iris_update_ip_opt(popt, IP_OPT_MAX, CM_LUT, level * 3 + 0, 0x01); + iris_update_ip_opt(popt, IP_OPT_MAX, CM_LUT, level * 3 + 1, 0x01); + len = iris_update_ip_opt( + popt, IP_OPT_MAX, CM_LUT, + level*3 + 2, (pqlt_cur_setting->source_switch == 0) ? 0x01 : skiplast); + + /*do not generate lut table for source switch.*/ + if (pqlt_cur_setting->source_switch == 0) { + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DPP, + 0xfc, 0xfc, skiplast); + } + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("cm color gamut=%d, len=%d", level, len); +} + +void iris_cm_color_gamut_pre_clear(void) +{ + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + + if (pqlt_cur_setting->source_switch != 0) { + pqlt_cur_setting->source_switch = 0; + iris_cm_color_gamut_set( + iris_setting.quality_cur.pq_setting.cmcolorgamut); + iris_cm_colortemp_mode_set( + iris_setting.quality_cur.pq_setting.cmcolortempmode); + } +} + +void iris_dpp_gamma_set(void) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + u32 gammalevel; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + if (pqlt_cur_setting->pq_setting.cmcolortempmode + == IRIS_COLOR_TEMP_OFF) + gammalevel = 0; /*use liner gamma if cm lut disable*/ + else + gammalevel = pqlt_cur_setting->pq_setting.cmcolorgamut + 1; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, GAMMA_LUT, + gammalevel, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +static int iris_lce_gamm1k_set( + struct iris_update_ipopt *popt, uint8_t skip_last) +{ + u32 dwLux_i, dwnBL_AL, dwGain, dwAHEGAMMA1K; + u32 level; + struct iris_update_regval regval; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + int len = 0; + uint32_t *payload = NULL; + + level = (pqlt_cur_setting->pq_setting.lcemode) * 6 + + pqlt_cur_setting->pq_setting.lcelevel; + payload = iris_get_ipopt_payload_data(IRIS_IP_LCE, level, 5); + + if (pqlt_cur_setting->pq_setting.alenable == true) { + if (pqlt_cur_setting->luxvalue > 20000) + pqlt_cur_setting->luxvalue = 20000; + + if (pqlt_cur_setting->luxvalue >= (m_dwTH_LuxAdj * 8)) + dwLux_i = MIN(8191, + (8 * m_dwTH_LuxAdj + pqlt_cur_setting->luxvalue / 8 - m_dwTH_LuxAdj)); + else + dwLux_i = pqlt_cur_setting->luxvalue; + + if (dwLux_i <= m_dwXLuxBuffer[0]) + dwnBL_AL = MIN(m_dwGLuxBuffer[0], + m_dwBLux + (m_dwKLuxBuffer[0] * dwLux_i) / 64); + else if (dwLux_i <= m_dwXLuxBuffer[1]) + dwnBL_AL = MIN(m_dwGLuxBuffer[1], + m_dwGLuxBuffer[0] + (m_dwKLuxBuffer[1] * (dwLux_i - m_dwXLuxBuffer[0])) / 64); + else if (dwLux_i <= m_dwXLuxBuffer[2]) + dwnBL_AL = MIN(m_dwGLuxBuffer[2], + m_dwGLuxBuffer[1] + (m_dwKLuxBuffer[2] * (dwLux_i - m_dwXLuxBuffer[1])) / 64); + else if (dwLux_i <= m_dwXLuxBuffer[3]) + dwnBL_AL = MIN(m_dwGLuxBuffer[3], + m_dwGLuxBuffer[2] + (m_dwKLuxBuffer[3] * (dwLux_i - m_dwXLuxBuffer[2])) / 64); + else if (dwLux_i <= m_dwXLuxBuffer[4]) + dwnBL_AL = MIN(m_dwGLuxBuffer[4], + m_dwGLuxBuffer[3] + (m_dwKLuxBuffer[4] * (dwLux_i - m_dwXLuxBuffer[3])) / 64); + else + dwnBL_AL = MIN(m_dwGLuxBuffer[5], + m_dwGLuxBuffer[4] + (m_dwKLuxBuffer[5] * (dwLux_i - m_dwXLuxBuffer[4])) / 64); + + if (dwnBL_AL < 1024) + dwGain = 0; + else + dwGain = dwnBL_AL - 1024; + + //max lux = 10000 -> 974, max lux = 20000 -> 976, + //max lux = 30000 -> 976, + dwAHEGAMMA1K = (dwGain * 90) / 976; + regval.ip = IRIS_IP_LCE; + regval.opt_id = 0xfd; + regval.mask = 0xffffffff; + regval.value = ((*payload) & 0x00ffffff) | (dwAHEGAMMA1K << 24); + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_LCE, + 0xfd, 0xfd, skip_last); + } + IRIS_LOGI("lux value=%d", pqlt_cur_setting->luxvalue); + return len; +} + +static int iris_lce_gamm1k_restore( + struct iris_update_ipopt *popt, uint8_t skip_last) +{ + u32 level; + struct iris_update_regval regval; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + int len = 0; + uint32_t *payload = NULL; + + + level = (pqlt_cur_setting->pq_setting.lcemode) * 6 + + pqlt_cur_setting->pq_setting.lcelevel; + payload = iris_get_ipopt_payload_data(IRIS_IP_LCE, level, 5); + + regval.ip = IRIS_IP_LCE; + regval.opt_id = 0xfd; + regval.mask = 0xffffffff; + regval.value = *payload; + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_LCE, + 0xfd, 0xfd, skip_last); + + IRIS_LOGI("%s, len = %d", __func__, len); + return len; +} + +void iris_lce_mode_set(u32 mode) +{ + u32 locallevel; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool skiplast = 0; + int len = 0; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + if (mode == IRIS_LCE_GRAPHIC) + locallevel = pqlt_cur_setting->pq_setting.lcelevel; + else + locallevel = pqlt_cur_setting->pq_setting.lcelevel + 6; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_LCE, locallevel, 0x01); + + if (pqlt_cur_setting->pq_setting.alenable == true + && pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) + len = iris_lce_gamm1k_set(popt, skiplast); + else + len = iris_lce_gamm1k_restore(popt, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("lce mode=%d, len=%d", mode, len); +} + +void iris_lce_level_set(u32 level) +{ + u32 locallevel; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + if (pqlt_cur_setting->pq_setting.lcemode + == IRIS_LCE_GRAPHIC) + locallevel = level; + else + locallevel = level + 6; + + len = iris_update_ip_opt( + popt, IP_OPT_MAX, IRIS_IP_LCE, locallevel, 0x01); + + /* hdr's al may use lce */ + if (pqlt_cur_setting->pq_setting.alenable == true + && pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) + len = iris_lce_gamm1k_set(popt, skiplast); + else + len = iris_lce_gamm1k_restore(popt, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("lce level=%d, len=%d", level, len); +} + +void iris_lce_graphic_det_set(bool enable) +{ + u32 locallevel; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + locallevel = 0x10 | (u8)enable; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_LCE, + locallevel, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("lce graphic det=%d, len=%d", enable, len); +} + +void iris_lce_al_set(bool enable) +{ + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (enable == true) + iris_lce_lux_set(); + else { + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + len = iris_lce_gamm1k_restore(popt, skiplast); + + len = iris_capture_enable_lce(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("%s, len = %d", __func__, len); + } + IRIS_LOGI("lce al enable=%d", enable); +} + +void iris_lce_demo_window_set(u32 vsize, u32 hsize, u8 inwnd) +{ + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool skiplast = 0; + int len = 0; + struct iris_update_ipopt popt[IP_OPT_MAX]; + uint32_t *payload = NULL; + bool is_ulps_enable = 0; + u32 level; + int data; + uint8_t path = iris_pq_update_path; + + IRIS_LOGI("%s E %d %d %d", __func__, vsize, hsize, inwnd); + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + // RESERVED + payload = iris_get_ipopt_payload_data(IRIS_IP_LCE, 0xF0, 2); + // payload[0]: RESERVED, + // [11:0] = DEMO_HSIZE, 0x00000FFF + // [27:16] = DEMO_VSIZE, 0x0FFF0000 + data = (payload[0] & (~0x0FFF0FFF)) | ((vsize & 0x0FFF) << 16) | (hsize & 0x0FFF); + iris_set_ipopt_payload_data(IRIS_IP_LCE, 0xF0, 2, data); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_LCE, 0xF0, 0x01); + + // NR_CTRL + level = (pqlt_cur_setting->pq_setting.lcemode) * 6 + + pqlt_cur_setting->pq_setting.lcelevel; + payload = iris_get_ipopt_payload_data(IRIS_IP_LCE, level, 2); + // BFRINC[17:10] + // bit14 = DEMO_H_EN + // bit15 = DEMO_V_EN + // bit17 = WND_CHANGE, 0: in window, 1: out of window + data = (payload[12] & (~0x0002C000)) | + ((hsize != 0 ? 1:0) << 14) | + ((vsize != 0 ? 1:0) << 15) | + ((inwnd & 0x01) << 17); + iris_set_ipopt_payload_data(IRIS_IP_LCE, level, 14, data); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_LCE, level, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("%s X %d %d %d, len=%d", __func__, vsize, hsize, inwnd, len); +} + + +void iris_dbc_level_set(u32 level) +{ + u32 locallevel; + u32 dbcenable; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + u8 localindex; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + dbcenable = (level > 0) ? 0x01 : 0x00; + locallevel = 0x10 | level; + + iris_dbc_lut_index ^= 1; + + IRIS_LOGI("send A/B %d", iris_dbc_lut_index); + + localindex = 0x20 | iris_dbc_lut_index; + iris_update_ip_opt(popt, IP_OPT_MAX, DBC_LUT, + DBC_OFF + level, 0x01); + iris_init_update_ipopt_t(popt, IP_OPT_MAX, DBC_LUT, + CABC_DLV_OFF + level, CABC_DLV_OFF + level, 0x01); + + iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DBC, + localindex, localindex, 0x01); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DBC, + dbcenable, skiplast); + /*len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DBC, locallevel, skiplast);*/ + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("dbc level=%d, len=%d", level, len); +} + +void iris_reading_mode_set(u32 level) +{ + u32 locallevel, locallevel_cm; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + // struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + //bool cm_csc_enable = true; + + /*only take affect when sdr2hdr bypass */ + if (pqlt_cur_setting->pq_setting.sdr2hdr == SDR2HDR_Bypass) { + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + locallevel = 0x40 | level; + // FIXME: WA for old pxlw-dtsi + // locallevel_cm = (pcfg->dual_setting ? 0x40 : 0x48) | level; + locallevel_cm = 0x40 | level; + + //if ((level == 0) && + // (pqlt_cur_setting->pq_setting.cm6axis == 0)) + // cm_csc_enable = false; + + //len = iris_cm_csc_set(popt, 0x01, cm_csc_enable); + + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_CM, + locallevel_cm, 0x01); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DPP, + locallevel, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + } + IRIS_LOGI("reading mode=%d", level); +} + +void iris_lce_lux_set(void) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + len = iris_lce_gamm1k_set(popt, skiplast); + + len = iris_capture_enable_lce(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("%s, len = %d", __func__, len); +} + +void iris_ambient_light_lut_set(uint32_t lut_offset) +{ +#define AL_SDR2HDR_INDEX_OFFSET 7 + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + bool skiplast = 0; + uint32_t *payload = NULL; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + if (pqlt_cur_setting->pq_setting.alenable == true) { + + if (pqlt_cur_setting->pq_setting.sdr2hdr >= HDR10In_ICtCp && + pqlt_cur_setting->pq_setting.sdr2hdr <= ICtCpIn_YCbCr) { + + if (!(iris_sdr2hdr_lut2ctl & 0xFFE00000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 2), 83); + iris_sdr2hdr_lut2ctl = payload[0]; + iris_sdr2hdr_lut2ctl = ((lut_offset<<19) | (0x17FFFF & iris_sdr2hdr_lut2ctl)); + iris_set_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 2), 83, iris_sdr2hdr_lut2ctl); + } + + if (!(iris_sdr2hdr_lutyctl & 0xFFFF0000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 2), 23); + iris_sdr2hdr_lutyctl = payload[0]; + } + + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, + (AL_SDR2HDR_INDEX_OFFSET + 2), 0x01); + + len = iris_update_ip_opt(popt, IP_OPT_MAX, AMBINET_SDR2HDR_LUT, + 0x0, skiplast); + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 2), 83); + } else if (pqlt_cur_setting->pq_setting.sdr2hdr >= SDR709_2_709 && + pqlt_cur_setting->pq_setting.sdr2hdr <= SDR709_2_2020) { + + if (!(iris_sdr2hdr_lut2ctl & 0xFFE00000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 5), 83); + iris_sdr2hdr_lut2ctl = payload[0]; + iris_sdr2hdr_lut2ctl = ((lut_offset<<19) | (0x17FFFF & iris_sdr2hdr_lut2ctl)); + iris_set_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 5), 83, iris_sdr2hdr_lut2ctl); + } + if (!(iris_sdr2hdr_lutyctl & 0xFFFF0000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 5), 23); + iris_sdr2hdr_lutyctl = payload[0]; + } + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, + (AL_SDR2HDR_INDEX_OFFSET + 5), 0x01); + //(AL_SDR2HDR_INDEX_OFFSET + + // pqlt_cur_setting->pq_setting.sdr2hdr), 0x01); + len = iris_update_ip_opt(popt, IP_OPT_MAX, AMBINET_SDR2HDR_LUT, + 0x0, skiplast); + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, (AL_SDR2HDR_INDEX_OFFSET + 5), 83); + } + } else { + u32 hdr_lut_idx; + + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, + pqlt_cur_setting->pq_setting.sdr2hdr, 0x01); + + if (!(iris_sdr2hdr_lut2ctl&0xFFE00000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, pqlt_cur_setting->pq_setting.sdr2hdr, 83); + iris_sdr2hdr_lut2ctl = payload[0]; + } + if (!(iris_sdr2hdr_lutyctl&0xFFFF0000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, pqlt_cur_setting->pq_setting.sdr2hdr, 23); + iris_sdr2hdr_lutyctl = payload[0]; + } + + if (pqlt_cur_setting->pq_setting.sdr2hdr >= HDR10In_ICtCp && pqlt_cur_setting->pq_setting.sdr2hdr <= ICtCpIn_YCbCr) { + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_LUT0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY2 << 4) & 0xf0); + len = iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, skiplast); + } else if (pqlt_cur_setting->pq_setting.sdr2hdr >= SDR709_2_709 && pqlt_cur_setting->pq_setting.sdr2hdr <= SDR709_2_2020) { + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_LUT0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_LUT1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_UVY2 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_INV_UV0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_INV_UV1 << 4) & 0xf0); + len = iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, skiplast); + } else { + hdr_lut_idx = ((pqlt_cur_setting->pq_setting.sdr2hdr-1) & 0xf) | ((SDR2HDR_LUT0 << 4) & 0xf0); + len = iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, skiplast); + } + } + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("al=%d hdr level=%d", + pqlt_cur_setting->pq_setting.alenable, + pqlt_cur_setting->pq_setting.sdr2hdr); +} + +void iris_maxcll_lut_set(u32 lutpos) +{ + int len; + struct iris_update_regval regval; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + if (!(iris_sdr2hdr_lutyctl & 0xFFFF0000)) { + len = iris_update_ip_opt(popt, IP_OPT_MAX, AMBINET_HDR_GAIN, 0x0, 1); + + regval.ip = IRIS_IP_SDR2HDR; + regval.opt_id = 0x92; + regval.mask = 0x0000FFFF; + regval.value = ((lutpos << 6) & 0xc0) | (iris_sdr2hdr_lutyctl & 0xFF3F); + iris_update_bitmask_regval_nonread(®val, false); + + iris_sdr2hdr_lutyctl_set(lutpos); + len += iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, + 0x92, 0x92, skiplast); + } else + len = iris_update_ip_opt(popt, IP_OPT_MAX, AMBINET_HDR_GAIN, 0x0, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("%s, len=%d", __func__, len); +} + + +void iris_dbclce_datapath_set(bool bEn) +{ + bool skiplast = 0; + int len; + u32 pwil_datapath; + uint32_t *payload = NULL; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + if (!iris_lce_power_status_get()) + bEn = 0;/*cannot enable lce dbc data path if power off*/ + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_datapath = (payload[2] & (~0x1)) | ((bEn == true) ? 0x00000001 : 0x00000000); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 4, pwil_datapath); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0xF1, skiplast); + + if ((!iris_capture_ctrl_en) + && (!iris_dynamic_power_get()) + && (!iris_debug_cap)) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x30, 0x30, 1); + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("dbclce_en=%d, len=%d", bEn, len); +} + + +void iris_dbclce_power_set(bool bEn) +{ + iris_lce_power_status_set(bEn); + iris_pmu_lce_set(bEn); +} + +void iris_sdr2hdr_level_set(u32 level) +{ + struct iris_update_regval regval; + u32 pwil_channel_order; + u32 pwil_csc; + u32 pwil_ctrl1, pwil_datapath, pwil_datapath1; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + u32 cm_csc = 0x40; + bool cm_csc_enable = true; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + u32 peaking_csc; + bool skiplast = 0; + u32 hdr_lut_idx = 0x01; + uint32_t *payload = NULL; + u32 gammalevel; + bool dma_sent = false; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + // struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if ((!iris_dynamic_power_get()) && (iris_capture_ctrl_en == true)) + skiplast = 1; + + if (pqlt_cur_setting->pq_setting.readingmode != 0) + cm_csc = 0x41; + + if ((level <= ICtCpIn_YCbCr) && (level >= HDR10In_ICtCp)) { + /*Not change iris_require_yuv_input due to magic code in ioctl.*/ + shadow_iris_HDR10 = true; + } else if (level == SDR709_2_709) { + shadow_iris_require_yuv_input = true; + shadow_iris_HDR10 = false; + } else { + shadow_iris_require_yuv_input = false; + shadow_iris_HDR10 = false; + shadow_iris_HDR10_YCoCg = false; + } + + if (level >= HDR10In_ICtCp && level <= SDR709_2_2020) { + iris_yuv_datapath = true; + //sdr2hdr level in irisconfigure start from 1, + //but lut table start from 0, so need -1. + //iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_EXT, + // 0x60 + level - 1, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_LUT0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + if (level >= HDR10In_ICtCp && level <= ICtCpIn_YCbCr) { + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_UVY0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_UVY1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_UVY2 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_INV_UV0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1)&0xf) | ((SDR2HDR_INV_UV1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + } else if (level >= SDR709_2_709 && level <= SDR709_2_2020) { + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_LUT1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_UVY0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_UVY1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_INV_UV0 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + hdr_lut_idx = ((level-1) & 0xf) | ((SDR2HDR_INV_UV1 << 4) & 0xf0); + iris_update_ip_opt(popt, IP_OPT_MAX, SDR2HDR_LUT, hdr_lut_idx, 0x01); + } + } else if (level == SDR2HDR_Bypass) { + iris_yuv_datapath = false; + } else { + IRIS_LOGE("%s something is wrong level=%d", __func__, level); + return; + } + + if ((level <= ICtCpIn_YCbCr) + && (level >= HDR10In_ICtCp)) { + /*channel order YUV, ICtCp*/ + pwil_channel_order = 0x60; + if (level == ICtCpIn_YCbCr) + pwil_csc = 0x91;/*pwil csc ICtCp to RGB. */ + else + pwil_csc = 0x90;/*pwil csc YUV to RGB*/ + pwil_datapath = 0x4008000; + pwil_datapath1 = 0; + if (shadow_iris_HDR10_YCoCg) {/*RGBlike solution*/ + pwil_channel_order = 0x62; + pwil_csc = 0x93; + pwil_datapath1 = 0x8000; + } + } else if (level == SDR709_2_709) { + pwil_channel_order = 0x60;/*channel order YUV*/ + pwil_csc = 0x92;/*pwil csc YUV to YUVFull */ + pwil_datapath = 0x4010000; + pwil_datapath1 = 0; + } else { + pwil_channel_order = 0x61;/*channel order RGB*/ + pwil_csc = 0x93;/*pwil csc default*/ + if (level == SDR2HDR_Bypass) { + pwil_csc = 0x95; + pwil_datapath = 0; + } else { + pwil_datapath = 0x4008000; + } + pwil_datapath1 = 0x8000; + } + switch (level) { + case HDR10In_ICtCp: + case HDR10In_YCbCr: + case ICtCpIn_YCbCr: + cm_csc = 0x45; + break; + case SDR709_2_709: + /*TODOS*/ + break; + case SDR709_2_p3: + cm_csc = 0x46; + break; + case SDR709_2_2020: + /*TODOS*/ + break; + default: + break; + } + + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, + pwil_channel_order, 0x01); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, + pwil_csc, 0x01); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + IRIS_LOGI("pwil ctrl1 %x", payload[0]); + pwil_datapath = (payload[2] & (~0x4018000)) | pwil_datapath; //CSC_MODE 18000 POST_PQ_PROCESS_EN 4000000 + pwil_datapath1 = (payload[3] & (~0x8020)) | pwil_datapath1; //UNPACK_BYPASS_EN + pwil_ctrl1 = (payload[1] & (~0x40)) | (iris_yuv_datapath ? 0x40 : 0x00); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 3, pwil_ctrl1); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 4, pwil_datapath); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 5, pwil_datapath1); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0xF1, 0x01); + + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, + level, 0x01); + + if (!(iris_sdr2hdr_lut2ctl & 0xFFE00000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, level, 83); + iris_sdr2hdr_lut2ctl = payload[0]; + } + if (!(iris_sdr2hdr_lutyctl & 0xFFFF0000)) { + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, level, 23); + iris_sdr2hdr_lutyctl = payload[0]; + } + + // FIXME: WA for old pxlw-dtsi + //if (!pcfg->dual_setting) + // cm_csc += 8; + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_CM, + cm_csc, 0x01); + + /*add the workaround to let hdr and cm lut */ + /*table take affect at the same time*/ + if (pqlt_cur_setting->pq_setting.cmcolortempmode > IRIS_COLOR_TEMP_OFF) + /*change ratio when source switch*/ + len = iris_cm_ratio_set(popt, 0x01); + + regval.ip = IRIS_IP_DPP; + regval.opt_id = 0xfc; + regval.mask = 0x00000031; + regval.value = (pqlt_cur_setting->pq_setting.cmcolortempmode == 0) + ? 0x00000020 : 0x00000011; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DPP, + 0xfc, 0xfc, 0x01); + + if (pqlt_cur_setting->source_switch == 1) { + /*use liner gamma if cm lut disable*/ + if (pqlt_cur_setting->pq_setting.cmcolortempmode == + IRIS_COLOR_TEMP_OFF) + gammalevel = 0; + else + gammalevel = pqlt_cur_setting->pq_setting.cmcolorgamut + 1; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, GAMMA_LUT, + gammalevel, 0x01); + } + + if (iris_yuv_datapath == true) + peaking_csc = 0x11; + else { + if ((pqlt_cur_setting->pq_setting.readingmode == 0) + && (pqlt_cur_setting->pq_setting.cm6axis == 0)) + cm_csc_enable = false; + + if (pqlt_cur_setting->pq_setting.peaking == 0) + peaking_csc = 0x11; + else + peaking_csc = 0x10; + } + + //len = iris_cm_csc_set(popt, 0x01, cm_csc_enable); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PEAKING, + peaking_csc, skiplast); + + if (!iris_dynamic_power_get() && (iris_capture_ctrl_en == true)) { + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DMA, + 0xe2, 0xe2, 0); + dma_sent = true; + } + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + if (dma_sent) { + IRIS_LOGD("AP csc prepare."); + iris_require_yuv_input = shadow_iris_require_yuv_input; + iris_HDR10 = shadow_iris_HDR10; + iris_HDR10_YCoCg = shadow_iris_HDR10_YCoCg; + pqlt_cur_setting->dspp_dirty = 1; + } + + pqlt_cur_setting->source_switch = 0; + IRIS_LOGI("sdr2hdr level =%d, len = %d", level, len); +} + +u32 iris_sdr2hdr_lut2ctl_get(void) +{ + if (iris_sdr2hdr_lut2ctl & 0xFFE00000) + return 0xFFE00000; + else if (iris_sdr2hdr_lut2ctl) + return (iris_sdr2hdr_lut2ctl & 0x80000)>>19; + else + return 15; +} + +void iris_sdr2hdr_lut2ctl_set(u32 value) +{ + IRIS_LOGI("Iris LUT2 Pos %d", value); + + if (value == 0xFFE00000) { + iris_sdr2hdr_lut2ctl = 0xFFE00000; + return; + } else if (value) + value = 1; + + iris_sdr2hdr_lut2ctl = ((value << 19) | (0x17FFFF & iris_sdr2hdr_lut2ctl)); +} + +u32 iris_sdr2hdr_lutyctl_get(void) +{ + if (iris_sdr2hdr_lutyctl & 0xFFFF0000) + return 0xFFFF0000; + else if (iris_sdr2hdr_lutyctl) + return (iris_sdr2hdr_lutyctl & 0xC0)>>6; + else + return 15; +} + +void iris_sdr2hdr_lutyctl_set(u32 value) +{ + if (value == 0xFFFF0000) + return; + else if (value) + value = 1; + + iris_sdr2hdr_lutyctl = ((value << 6) | (0xFF3F & iris_sdr2hdr_lutyctl)); + IRIS_LOGI("iris_sdr2hdr_lutyctl %x", iris_sdr2hdr_lutyctl); +} + +void iris_peaking_idle_clk_enable(bool enable) +{ + u32 locallevel; + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + locallevel = 0xa0 | (u8)enable; + len = iris_capture_disable_pq(popt, &skiplast); + + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PEAKING, + locallevel, locallevel, skiplast); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("peaking idle clk enable=%d", enable); +} + +void iris_cm_6axis_seperate_gain(u8 gain_type, u32 value) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + struct iris_update_regval regval; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + len = iris_capture_disable_pq(popt, &skiplast); + + regval.ip = IRIS_IP_CM; + /*6 axis separate gain id start from 0xb0*/ + regval.opt_id = 0xb0 + gain_type; + regval.mask = 0x00fc0000; + regval.value = value << 18; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_CM, + regval.opt_id, regval.opt_id, skiplast); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("cm gain type = %d, value = %d, len = %d", + gain_type, value, len); +} + +void iris_pwm_freq_set(u32 value) +{ + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct iris_update_regval regval; + u32 regvalue = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + regvalue = 1000000 / value; + regvalue = (27000000 / 1024) / regvalue; + + regval.ip = IRIS_IP_PWM; + regval.opt_id = 0xfd; + regval.mask = 0xffffffff; + regval.value = regvalue; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWM, + 0xfd, 0xfd, 0); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("%s, blc_pwm freq=%d", __func__, regvalue); +} + +void iris_pwm_enable_set(bool enable) +{ + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWM, enable, 0); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("%s, blc_pwm enable=%d", __func__, enable); +} + +void iris_dbc_bl_user_set(u32 value) +{ + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct iris_update_regval regval; + u32 regvalue = 0; + bool skiplast = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (iris_setting.quality_cur.pq_setting.dbc == 0) + return; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + /*if ((!iris_dynamic_power_get()) */ + /*&& (iris_lce_power_status_get()))*/ + len = iris_capture_disable_lce(popt, &skiplast); + + regvalue = (value * 0xfff) / 0xff; + + regval.ip = IRIS_IP_DBC; + regval.opt_id = 0xfd; + regval.mask = 0xffffffff; + regval.value = regvalue; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DBC, + 0xfd, 0xfd, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("%s,bl_user value=%d", __func__, regvalue); +} + +void iris_dbc_led0d_gain_set(u32 value) +{ + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct iris_update_regval regval; + bool skiplast = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_lce(popt, &skiplast); + + regval.ip = IRIS_IP_DBC; + regval.opt_id = 0xfc; + regval.mask = 0xffffffff; + regval.value = value; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DBC, + regval.opt_id, regval.opt_id, skiplast); + + len = iris_capture_enable_lce(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("%s,dbc_led0d value=%d", __func__, value); +} + +void iris_panel_nits_set(u32 bl_ratio, bool bSystemRestore, int level) +{ +#if 0 + char led_pwm1[3] = {MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x0, 0x0}; + char hbm_data[2] = {MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x0}; + struct dsi_cmd_desc backlight_cmd = { + {0, MIPI_DSI_DCS_LONG_WRITE, 0, 0, 0, sizeof(led_pwm1), led_pwm1, 0, NULL}, 1, 1}; + struct dsi_cmd_desc hbm_cmd = { + {0, MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0, 0, 0, sizeof(hbm_data), hbm_data, 0, NULL}, 1, 1}; + + struct dsi_panel_cmd_set cmdset = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &backlight_cmd, + }; + u32 bl_lvl; + struct iris_cfg *pcfg = iris_get_cfg(); + + /* Don't control panel's brightness when sdr2hdr mode is 3 */ + if (iris_sdr2hdr_mode == 3) + return; + + if (bSystemRestore) + bl_lvl = iris_setting.quality_cur.system_brightness; + else + bl_lvl = bl_ratio * pcfg->panel_dimming_brightness / PANEL_BL_MAX_RATIO; + + if (pcfg->panel->bl_config.bl_max_level > 255) { + led_pwm1[1] = (unsigned char)(bl_lvl >> 8); + led_pwm1[2] = (unsigned char)(bl_lvl & 0xff); + } else { + led_pwm1[1] = (unsigned char)(bl_lvl & 0xff); + backlight_cmd.msg.tx_len = 2; + } + iris_pt_send_panel_cmd(pcfg->panel, &cmdset); + + // Support HBM for different panels. + hbm_data[1] = (bSystemRestore) ? pcfg->panel_hbm[0] : pcfg->panel_hbm[1]; + cmdset.cmds = &hbm_cmd; + if (pcfg->panel_hbm[0] != pcfg->panel_hbm[1]) + iris_pt_send_panel_cmd(pcfg->panel, &cmdset); + IRIS_LOGD("panel_nits: bl_lvl=0x%x, hbm=0x%x, restore=%d", bl_lvl, hbm_data[1], bSystemRestore); +#endif +} + + +void iris_scaler_filter_update(u8 scaler_type, u32 level) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + int len; + uint8_t ip; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (scaler_type == SCALER_INPUT) + ip = SCALER1D_LUT; + else + ip = SCALER1D_PP_LUT; + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, ip, + level, level, 0); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("scaler filter level=%d", level); +} + + +void iris_scaler_gamma_enable(bool lightup_en, u32 level) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + bool skiplast = 0; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (lightup_en == false) + len = iris_capture_disable_pq(popt, &skiplast); + else { + if (!iris_dynamic_power_get()) + skiplast = 1; + } + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DPP, + level, skiplast); + + if (lightup_en == false) + len = iris_capture_enable_pq(popt, len); + else { + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + } + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("gamma enable=%d", level); +} + + +void iris_hdr_csc_prepare(void) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + int len; + bool skiplast = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (iris_capture_ctrl_en == false) { + IRIS_LOGD("iris csc prepare."); + iris_capture_ctrl_en = true; + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (!iris_dynamic_power_get() && !iris_skip_dma) + skiplast = 1; + + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x52, 0x52, skiplast); + if (!iris_dynamic_power_get() && !iris_skip_dma) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DMA, + 0xe2, 0xe2, 0); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + } +} + +static void iris_dynamic_vfr(struct iris_cfg *pcfg, struct dsi_display *display) +{ + if (iris_virtual_display(display)) { + int video_update_wo_osd = atomic_read(&pcfg->video_update_wo_osd); + + IRIS_LOGV("clean video_update_wo_osd"); + atomic_set(&pcfg->video_update_wo_osd, 0); + if (video_update_wo_osd >= 4) { + cancel_work_sync(&pcfg->vfr_update_work); + schedule_work(&pcfg->vfr_update_work); + } + } else { + IRIS_LOGV("video_update_wo_osd: %d", atomic_read(&pcfg->video_update_wo_osd)); + atomic_inc(&pcfg->video_update_wo_osd); + if (atomic_read(&pcfg->video_update_wo_osd) == 4) { + cancel_work_sync(&pcfg->vfr_update_work); + schedule_work(&pcfg->vfr_update_work); + } + } +} + +int iris_kickoff(void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + struct iris_cfg *pcfg; + + if (phys_encoder == NULL) + return -EFAULT; + if (phys_encoder->connector == NULL) + return -EFAULT; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return -EFAULT; + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + display = c_conn->display; + if (display == NULL) + return -EFAULT; + + pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + if (pcfg->fod_pending) + iris_post_fod(pcfg->panel); + if (pcfg->dynamic_vfr) + iris_dynamic_vfr(pcfg, display); + if (iris_virtual_display(display) || pcfg->valid < PARAM_PARSED) + return 0; + + complete(&pcfg->frame_ready_completion); + return 0; +} + +void iris_hdr_csc_complete(int step) +{ + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (step == 0 || step == 1 || step == 3 || step == 4) { + IRIS_LOGD("AP csc prepare."); + iris_require_yuv_input = shadow_iris_require_yuv_input; + iris_HDR10 = shadow_iris_HDR10; + iris_HDR10_YCoCg = shadow_iris_HDR10_YCoCg; + iris_setting.quality_cur.dspp_dirty = 1; + if (step == 4) + return; + } else if (step == 5 || step == 6) { + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGD("Wait frame ready."); + reinit_completion(&pcfg->frame_ready_completion); + if (!wait_for_completion_timeout(&pcfg->frame_ready_completion, + msecs_to_jiffies(50))) + IRIS_LOGE("%s: timeout waiting for frame ready", __func__); + } + + IRIS_LOGD("AP csc complete."); + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (iris_capture_ctrl_en == true) { + if (!iris_dynamic_power_get()) { + skiplast = 1; + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x30, 0x30, 1); + } + + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PWIL, + 0x51, 0x51, skiplast); + + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DMA, + 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("iris csc complete."); + iris_capture_ctrl_en = false; + } else { + if (!iris_dynamic_power_get()) { + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGD("iris csc complete."); + } + } +} + + +int32_t iris_update_ip_opt( + struct iris_update_ipopt *popt, int len, + uint8_t ip, uint8_t opt_id, uint8_t skip_last) +{ + int i = 0; + uint8_t old_opt; + int32_t cnt = 0; + + struct iris_pq_ipopt_val *pq_ipopt_val = iris_get_cur_ipopt_val(ip); + + if (pq_ipopt_val == NULL) { + IRIS_LOGI("can not get pq ipot val ip = %02x, opt_id = %02x", + ip, opt_id); + return 1; + } + + if (0 /*ip == IRIS_IP_EXT*/) { + if ((opt_id & 0xe0) == 0x40) { /*CM LUT table*/ + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + if (((opt_id & 0x1f)%CM_LUT_GROUP) + == (((pq_ipopt_val->popt[i]) & 0x1f) + % CM_LUT_GROUP)) { + old_opt = pq_ipopt_val->popt[i]; + pq_ipopt_val->popt[i] = opt_id; + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + } else if (((opt_id & 0xe0) == 0x60) + || ((opt_id & 0xe0) == 0xa0) + || ((opt_id & 0xe0) == 0xe0)) { + /*SDR2HDR LUT table and gamma table*/ + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + if ((opt_id & 0xe0) + == ((pq_ipopt_val->popt[i]) & 0xe0)) { + old_opt = pq_ipopt_val->popt[i]; + pq_ipopt_val->popt[i] = opt_id; + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + } else { /*DBC LUT table*/ + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + if (((opt_id & 0xe0) + == ((pq_ipopt_val->popt[i]) & 0xe0)) + && (((pq_ipopt_val->popt[i]) & 0x1f) != 0)) { + + old_opt = pq_ipopt_val->popt[i]; + pq_ipopt_val->popt[i] = opt_id; + + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + } + } + + if (ip == DBC_LUT) { + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + old_opt = pq_ipopt_val->popt[i]; + /*init lut can not change*/ + if (old_opt < CABC_DLV_OFF && (old_opt & 0x7f) != 0) { + pq_ipopt_val->popt[i] = opt_id; + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + } + + if (ip == CM_LUT) { + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + if ((opt_id % CM_LUT_GROUP) + == (pq_ipopt_val->popt[i] + % CM_LUT_GROUP)) { + old_opt = pq_ipopt_val->popt[i]; + pq_ipopt_val->popt[i] = opt_id; + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + } + + for (i = 0; i < pq_ipopt_val->opt_cnt; i++) { + if ((opt_id & 0xf0) == ((pq_ipopt_val->popt[i]) & 0xf0)) { + old_opt = pq_ipopt_val->popt[i]; + pq_ipopt_val->popt[i] = opt_id; + cnt = iris_init_update_ipopt_t(popt, len, ip, + old_opt, opt_id, skip_last); + return cnt; + } + } + return 1; +} + +uint32_t iris_frc_variable_set(int frc_var_disp) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + struct iris_update_regval regval; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + regval.ip = IRIS_IP_PWIL; + regval.opt_id = 0x23; + regval.mask = 0x00000100; + regval.value = frc_var_disp << 8; + + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, regval.ip, + regval.opt_id, regval.opt_id, skiplast); + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + + IRIS_LOGI("%s, regval.value=%x", __func__, regval.value); + return regval.value; +} + +void iris_frc_force_repeat(bool enable) +{ + struct iris_update_regval regval; + + regval.ip = IRIS_IP_PWIL; + regval.opt_id = 0xD1; + regval.mask = 0x00000040; + regval.value = (enable ? 0x40 : 0x00); + iris_update_bitmask_regval(®val, true); +} + +void iris_pwil_frc_pt_set(int frc_pt_switch_on) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + uint32_t *payload = NULL; + u32 pwil_datapath = frc_pt_switch_on ? 0x80000000 : 0x0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_datapath = (payload[2] & (~0x80000000)) | pwil_datapath; + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 4, pwil_datapath); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, 0x01); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +void iris_pwil_frc_ratio_set(int out_fps_ratio, int in_fps_ratio) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + uint32_t *payload = NULL; + int temp = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF4, 2); + temp = (payload[9] & (~0xff000000)) | (out_fps_ratio<<24); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF4, 11, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF4, 0x01); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xD0, 2); + temp = (payload[5] & (~0x00003F00)) | (in_fps_ratio<<8); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xd0, 7, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xD0, 0x01); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +void iris_pwil_frc_video_ctrl2_set(int mvc_0_1_phase) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + uint32_t *payload = NULL; + int temp = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xB0, 2); + temp = (payload[2] & (~0x80000000)) | (mvc_0_1_phase<<31); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xb0, 4, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xB0, 0x01); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +void iris_pwil_cmd_disp_mode_set(bool cmd_disp_on) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len = 0; + uint32_t *payload = NULL; + struct iris_cfg *pcfg = iris_get_cfg(); + u32 pwil_ctrl = (cmd_disp_on && pcfg->tx_mode) ? 0x10 : 0x0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (!iris_dynamic_power_get()) + skiplast = 1; + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_ctrl = (payload[0] & (~0x10)) | pwil_ctrl; + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2, pwil_ctrl); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, skiplast); + + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +void iris_psf_mif_efifo_set(u8 mode, bool osd_enable) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct iris_update_regval regval; + bool enable = false; + bool skiplast = 0; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + /* disable efifo */ + if (true) + return; + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (!iris_dynamic_power_get()) + skiplast = 1; + if ((mode == PT_MODE) && (osd_enable == true)) + enable = true; + + regval.ip = IRIS_IP_PSR_MIF; + regval.opt_id = pcfg->dual_setting ? 0xfe : 0xfd; + regval.mask = 0x1000; + regval.value = ((enable == true) ? 0 : 0x1000); + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PSR_MIF, + regval.opt_id, regval.opt_id, skiplast); + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("mode = %d, regval.value = 0x%x, len = %d", mode, regval.value, len); +} + +void iris_psf_mif_dyn_addr_set(bool dyn_addr_enable) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + struct iris_update_regval regval; + bool skiplast = 0; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + + regval.ip = IRIS_IP_PSR_MIF; + regval.opt_id = pcfg->dual_setting ? 0xfe : 0xfd; + regval.mask = 0x2000; + regval.value = ((dyn_addr_enable == false) ? 0 : 0x2000); + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, IRIS_IP_PSR_MIF, + regval.opt_id, regval.opt_id, skiplast); + if (!dyn_addr_enable) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + IRIS_LOGI("regval.value = 0x%x, len = %d", regval.value, len); +} + +// -1: no update, 0: disable, 1: enable +void iris_ms_pwil_dma_update(struct iris_mspwil_parameter *par) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + struct iris_update_regval regval; + uint32_t pwil_ad_frc_info; + uint32_t *payload = NULL; + u32 pwil_datapath = par->frc_pt_switch_on ? 0x80000000 : 0x0; + u32 pwil_ctrl = (par->cmd_disp_on && pcfg->tx_mode) ? 0x10 : 0x0; + int temp = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + // uint32_t tx_reserve_0; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + // frc_var_disp, 0xf1240108 + if (par->frc_var_disp != -1) { + // MIPI_TX ECO + // payload = iris_get_ipopt_payload_data(IRIS_IP_TX, 0x00, 2); + // if (payload && payload[15] == 0xf1880038) { + // tx_reserve_0 = payload[16]; + // tx_reserve_0 &= ~(1<<28); + // tx_reserve_0 |= par->frc_var_disp << 28; + // iris_set_ipopt_payload_data(IRIS_IP_TX, 0x00, 2+16, tx_reserve_0); + // len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_TX, 0x00, 0x01); + // } else { + // pr_err("cannot find IRIS_TX_RESERVE_0, payload[15]: %x\n", payload[15]); + // } + + regval.ip = IRIS_IP_PWIL; + regval.opt_id = 0x23; + regval.mask = 0x00000100; + regval.value = par->frc_var_disp << 8; + iris_update_bitmask_regval_nonread(®val, false); + len = iris_init_update_ipopt_t(popt, IP_OPT_MAX, regval.ip, + regval.opt_id, regval.opt_id, 1); + pwil_ad_frc_info = regval.value; + IRIS_LOGI("%s, pwil_ad_frc_info=%x", __func__, pwil_ad_frc_info); + } + + // type: 0x0001000C + // frc_pt_switch_on, 0xf1240008 + if (par->frc_pt_switch_on != -1) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_datapath = (payload[2] & (~0x80000000)) | pwil_datapath; + pwil_datapath &= ~0x00800000; // blending before scale(PP) + if (pcfg->dual_setting && par->frc_pt_switch_on == 0) + pwil_datapath |= 0x00800000; // blending after scale(PP) + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 4, pwil_datapath); + // len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, 0x01); + } + // cmd_disp_on, 0xf1240000 + if (par->cmd_disp_on != -1) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_ctrl = (payload[0] & (~0x10)) | pwil_ctrl; + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2, pwil_ctrl); + // len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, 0x01); + } + + if (par->frc_pt_switch_on != -1 || par->cmd_disp_on != -1) + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, 0x01); + + if (par->ratio_update) { + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF4, 2); + temp = (payload[9] & (~0xff000000)) | (par->out_fps_ratio<<24); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF4, 11, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF4, 0x01); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xD0, 2); + temp = (payload[5] & (~0x00003F00)) | (par->in_fps_ratio<<8); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xd0, 7, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xD0, 0x01); + } + + if (par->mvc_01phase_update) { + int pwil_video_opt = 0xB0; + if (pcfg->dual_setting) + pwil_video_opt = 0xB1; + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, pwil_video_opt, 2); + temp = (payload[2] & (~0x80000000)) | (par->mvc_01phase<<31); + iris_set_ipopt_payload_data(IRIS_IP_PWIL, pwil_video_opt, 4, temp); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, pwil_video_opt, 0x01); + } + + len = iris_capture_enable_pq(popt, len); + if (!iris_frc_dma_disable) { + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + } + +} + +void iris_dtg_frame_rate_set(u32 framerate) +{ + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + if (framerate == HIGH_FREQ) + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DTG, 0x1, 0x0); + else + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DTG, 0x0, 0x0); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DTG, 0xF0, 0x0); + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + +} + +static ssize_t iris_pq_config_write(struct file *file, const char __user *buff, + size_t count, loff_t *ppos) +{ + unsigned long val; + struct iris_cfg_log { + uint8_t type; + char *str; + }; + + struct iris_cfg_log arr[] = { + {IRIS_PEAKING, "IRIS_PEAKING"}, + {IRIS_DBC_LEVEL, "IRIS_DBC_LEVEL"}, + {IRIS_LCE_LEVEL, "IRIS_LCE_LEVEL"}, + {IRIS_DEMO_MODE, "IRIS_DEMO_MODE"}, + {IRIS_SDR2HDR, "IRIS_SDR2HDR"}, + {IRIS_DYNAMIC_POWER_CTRL, "IRIS_DYNAMIC_POWER_CTRL"}, + {IRIS_LCE_MODE, "IRIS_LCE_MODE"}, + {IRIS_GRAPHIC_DET_ENABLE, "IRIS_GRAPHIC_DET_ENABLE"}, + {IRIS_HDR_MAXCLL, "IRIS_HDR_MAXCLL"}, + {IRIS_ANALOG_BYPASS_MODE, "IRIS_ANALOG_BYPASS_MODE"}, + {IRIS_CM_6AXES, "IRIS_CM_6AXES"}, + {IRIS_CM_FTC_ENABLE, "IRIS_CM_FTC_ENABLE"}, + {IRIS_S_CURVE, "IRIS_S_CURVE"}, + {IRIS_CM_COLOR_TEMP_MODE, "IRIS_CM_COLOR_TEMP_MODE"}, + {IRIS_CM_COLOR_GAMUT, "IRIS_CM_COLOR_GAMUT"}, + {IRIS_CM_COLOR_GAMUT_PRE, "IRIS_CM_COLOR_GAMUT_PRE"}, + {IRIS_CCT_VALUE, "IRIS_CCT_VALUE"}, + {IRIS_COLOR_TEMP_VALUE, "IRIS_COLOR_TEMP_VALUE"}, + {IRIS_AL_ENABLE, "IRIS_AL_ENABLE"}, + {IRIS_LUX_VALUE, "IRIS_LUX_VALUE"}, + {IRIS_READING_MODE, "IRIS_READING_MODE"}, + {IRIS_CHIP_VERSION, "IRIS_CHIP_VERSION"}, + {IRIS_PANEL_TYPE, "IRIS_PANEL_TYPE"}, + {IRIS_LCE_DEMO_WINDOW, "IRIS_LCE_DEMO_WINDOW"}, + }; + u32 type; + u32 value; + int i = 0; + uint32_t cfg_val = 0; + int len = (sizeof(arr))/(sizeof(arr[0])); + + if (kstrtoul_from_user(buff, count, 0, &val)) + return -EFAULT; + + type = (val & 0xffff0000) >> 16; + value = (val & 0xffff); + iris_configure(DSI_PRIMARY, type, value); + + for (i = 0; i < len; i++) { + iris_configure_get(DSI_PRIMARY, arr[i].type, 1, &cfg_val); + IRIS_LOGI("%s: %d", arr[i].str, cfg_val); + } + + return count; +} + +static const struct file_operations iris_pq_config_fops = { + .open = simple_open, + .write = iris_pq_config_write, +}; + + +int iris_dbgfs_pq_init(struct dsi_display *display) +{ + struct iris_cfg *pcfg; + + pcfg = iris_get_cfg(); + + if (pcfg->dbg_root == NULL) { + pcfg->dbg_root = debugfs_create_dir("iris", NULL); + if (IS_ERR_OR_NULL(pcfg->dbg_root)) { + IRIS_LOGE("debugfs_create_dir for iris_debug failed, error %ld", + PTR_ERR(pcfg->dbg_root)); + return -ENODEV; + } + } + if (debugfs_create_file("iris_pq_config", 0644, pcfg->dbg_root, display, + &iris_pq_config_fops) == NULL) { + IRIS_LOGE("%s(%d): debugfs_create_file: index fail", + __FILE__, __LINE__); + return -EFAULT; + } + return 0; +} + +int iris_update_backlight(u8 pkg_mode, u32 bl_lvl) +{ + int rc = 0; + struct iris_cfg *pcfg = NULL; + struct mipi_dsi_device *dsi; + struct dsi_panel *panel; + char led_pwm1[3] = {MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x0, 0x0}; + struct dsi_cmd_desc backlight_cmd = { + {0, MIPI_DSI_DCS_LONG_WRITE, 0, 0, 0, sizeof(led_pwm1), led_pwm1, 0, NULL}, 1, 1}; + + struct dsi_panel_cmd_set cmdset = { + .state = DSI_CMD_SET_STATE_HS, + .count = 1, + .cmds = &backlight_cmd, + }; + + pcfg = iris_get_cfg(); + panel = pcfg->panel; + dsi = &panel->mipi_device; + + iris_setting.quality_cur.system_brightness = bl_lvl; + /* Don't set panel's brightness during HDR/SDR2HDR */ + /* Set panel's brightness when sdr2hdr mode is 3 */ + if (iris_setting.quality_cur.pq_setting.sdr2hdr != SDR2HDR_Bypass && iris_sdr2hdr_mode != 3) + return rc; + + if (panel->bl_config.bl_max_level > 255) { + if (pkg_mode) { + led_pwm1[1] = (unsigned char)(bl_lvl >> 8); + led_pwm1[2] = (unsigned char)(bl_lvl & 0xff); + } else { + led_pwm1[1] = (unsigned char)(bl_lvl & 0xff); + led_pwm1[2] = (unsigned char)(bl_lvl >> 8); + } + } else { + led_pwm1[1] = (unsigned char)(bl_lvl & 0xff); + backlight_cmd.msg.tx_len = 2; + } + + if (pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE) + rc = iris_pt_send_panel_cmd(panel, &cmdset); + else + rc = iris_dsi_send_cmds(panel, cmdset.cmds, cmdset.count, cmdset.state); + + return rc; +} + +void iris_pwil_sdr2hdr_resolution_set(bool enter_frc_mode) +{ + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + struct iris_cfg *pcfg = NULL; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len = 0; + uint32_t *payload = NULL; + u32 resolution = 0, num_ratio = 0; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + if (pqlt_cur_setting->pq_setting.sdr2hdr >= SDR709_2_p3 && pqlt_cur_setting->pq_setting.sdr2hdr <= SDR709_2_2020) { + pcfg = iris_get_cfg(); + iris_init_ipopt_ip(popt, IP_OPT_MAX); + if (enter_frc_mode) { + num_ratio = (1<<28) / (pcfg->frc_setting.memc_hres * pcfg->frc_setting.memc_vres); + resolution = (pcfg->frc_setting.memc_vres & 0xFFF) | (pcfg->frc_setting.memc_hres & 0xFFF)<<16; + } else { + num_ratio = (1<<28) / (pcfg->frc_setting.disp_vres * pcfg->frc_setting.disp_hres); + resolution = (pcfg->frc_setting.disp_vres & 0xFFF) | (pcfg->frc_setting.disp_hres & 0xFFF)<<16; + } + + if (!iris_dynamic_power_get()) + skiplast = 1; + + payload = iris_get_ipopt_payload_data(IRIS_IP_SDR2HDR, 0x93, 2); + iris_set_ipopt_payload_data(IRIS_IP_SDR2HDR, 0x93, 2, resolution); + iris_set_ipopt_payload_data(IRIS_IP_SDR2HDR, 0x93, 3, num_ratio); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_SDR2HDR, 0x93, skiplast); + + if (!iris_dynamic_power_get()) + len = iris_init_update_ipopt_t( + popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + } +} + +void iris_dom_set(int mode) +{ + // struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool skiplast = 0; + int len; + bool is_ulps_enable = 0; + uint32_t *payload = NULL; + uint8_t path = iris_pq_update_path; + uint32_t dport_ctrl0; + + // IRIS_LOGD("%s, mode: %d, DOM cnt: %d-%d", __func__, mode, pcfg->dom_cnt_in_ioctl, pcfg->dom_cnt_in_frc); + // if (mode != 0) { + // if (atomic_read(&pcfg->dom_cnt_in_ioctl) && atomic_read(&pcfg->dom_cnt_in_frc)) { + // IRIS_LOGI("%s, both set dom in ioctl and frc", __func__); + // atomic_set(&pcfg->dom_cnt_in_frc, 0); + // return; + // } + // } + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + payload = iris_get_ipopt_payload_data(IRIS_IP_DPORT, 0xF0, 2); + dport_ctrl0 = payload[0]; + dport_ctrl0 &= ~0xc000; + dport_ctrl0 |= (mode & 0x3) << 14; + iris_set_ipopt_payload_data(IRIS_IP_DPORT, 0xF0, 2, dport_ctrl0); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DPORT, 0xF0, skiplast); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_DPORT, 0x80, skiplast); + + len = iris_capture_enable_pq(popt, len); + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); + // if (mode == 0) + // atomic_set(&pcfg->dom_cnt_in_ioctl, 1); + // else + // atomic_set(&pcfg->dom_cnt_in_ioctl, 0); +} + +static int iris_brightness_para_set(struct iris_update_ipopt *popt, uint8_t skip_last, uint32_t *value) +{ + int32_t ip = 0; + int32_t opt_id = 0; + uint32_t *data = NULL; + uint32_t val = 0; + int len = 0; + struct iris_ip_opt *psopt; + + if (value == NULL) { + IRIS_LOGE("brightness value is empty"); + return 0; + } + + ip = IRIS_IP_DPP; + opt_id = 0x40; + psopt = iris_find_ip_opt(ip, opt_id); + if (psopt == NULL) { + IRIS_LOGE("can not find ip = %02x opt_id = %02x", ip, opt_id); + return 1; + } + + data = (uint32_t *)psopt->cmd[0].msg.tx_buf; + val = value[0]; + val &= 0x7fff7fff; + data[3] = val; + val = value[1]; + val &= 0x7fff7fff; + data[4] = val; + val = value[2]; + val &= 0x7fff7fff; + data[5] = val; + val = value[3]; + val &= 0x7fff7fff; + data[6] = val; + val = value[4]; + val &= 0x00007fff; + data[7] = val; + + len = iris_update_ip_opt(popt, IP_OPT_MAX, ip, opt_id, skip_last); + + return len; +} + +void iris_brightness_level_set(u32 *value) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + + + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + len = iris_brightness_para_set(popt, skiplast, value); + len = iris_capture_enable_pq(popt, len); + + // TODO: improve performance + // iris_init_ipopt_ip(popt, IP_OPT_MAX); + // len = iris_brightness_para_set(popt, skiplast, value); + // if (!iris_dynamic_power_get() && !iris_skip_dma) { + // len = iris_init_update_ipopt_t( + // popt, IP_OPT_MAX, IRIS_IP_DMA, 0xe2, 0xe2, 0); + // } + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} + +int32_t iris_parse_color_temp_range(struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + + /* 2500K~7500K for default */ + pcfg->min_color_temp = 2500; + pcfg->max_color_temp = 7500; + + rc = of_property_read_u32(np, "pxlw,min-color-temp", &(pcfg->min_color_temp)); + if (rc) { + IRIS_LOGE("can not get property: pxlw,min-color-temp"); + return rc; + } + IRIS_LOGI("pxlw,min-color-temp: %d", pcfg->min_color_temp); + + rc = of_property_read_u32(np, "pxlw,max-color-temp", &(pcfg->max_color_temp)); + if (rc) { + IRIS_LOGE("can not get property:pxlw,max-color-temp"); + return rc; + } + IRIS_LOGI("pxlw,max-color-temp: %d", pcfg->max_color_temp); + + return rc; +} + +static int32_t _iris_count_ip(const uint8_t *data, int32_t len, int32_t *pval) +{ + int tmp = 0; + int i = 0; + int j = 0; + + if (data == NULL || len == 0 || pval == NULL) { + IRIS_LOGE("%s(), invalid data or pval or len", __func__); + return -EINVAL; + } + + tmp = data[0]; + len = len >> 1; + + for (i = 0; i < len; i++) { + if (tmp == data[2 * i]) { + pval[j]++; + } else { + tmp = data[2 * i]; + j++; + pval[j]++; + } + } + + /*j begin from 0*/ + return j + 1; +} + +static int32_t _iris_alloc_pq_init_space(struct iris_cfg *pcfg, + const uint8_t *pdata, int32_t item_cnt) +{ + int32_t i = 0; + int32_t size = 0; + int32_t ip_cnt = 0; + int32_t rc = 0; + int32_t *ptr = NULL; + struct iris_pq_init_val *pinit_val = &pcfg->pq_init_val; + + if (pdata == NULL || item_cnt == 0) { + IRIS_LOGE("%s(), invalide input, data: %p, size: %d", pdata, item_cnt); + return -EINVAL; + } + + size = sizeof(*ptr) * (item_cnt >> 1); + ptr = vmalloc(size); + if (ptr == NULL) { + IRIS_LOGE("can not malloc space for ptr"); + return -EINVAL; + } + memset(ptr, 0x00, size); + + ip_cnt = _iris_count_ip(pdata, item_cnt, ptr); + if (ip_cnt <= 0) { + IRIS_LOGE("can not static ip option"); + rc = -EINVAL; + goto EXIT_FREE; + } + + pinit_val->ip_cnt = ip_cnt; + size = sizeof(struct iris_pq_ipopt_val) * ip_cnt; + pinit_val->val = vmalloc(size); + if (pinit_val->val == NULL) { + IRIS_LOGE("can not malloc pinit_val->val"); + rc = -EINVAL; + goto EXIT_FREE; + } + + for (i = 0; i < ip_cnt; i++) { + pinit_val->val[i].opt_cnt = ptr[i]; + size = sizeof(uint8_t) * ptr[i]; + pinit_val->val[i].popt = vmalloc(size); + } + +EXIT_FREE: + vfree(ptr); + ptr = NULL; + + return rc; +} +int32_t iris_parse_default_pq_param(struct device_node *np, + struct iris_cfg *pcfg) +{ + int32_t i = 0; + int32_t j = 0; + int32_t k = 0; + int32_t item_cnt = 0; + int32_t rc = 0; + const uint8_t *key = "pxlw,iris-pq-default-val"; + const uint8_t *pdata = NULL; + struct iris_pq_init_val *pinit_val = &pcfg->pq_init_val; + + pdata = of_get_property(np, key, &item_cnt); + if (!pdata) { + IRIS_LOGE("%s pxlw,iris-pq-default-val fail", __func__); + return -EINVAL; + } + + rc = _iris_alloc_pq_init_space(pcfg, pdata, item_cnt); + if (rc) { + IRIS_LOGE("malloc error"); + return rc; + } + + for (i = 0; i < pinit_val->ip_cnt; i++) { + struct iris_pq_ipopt_val *pval = &(pinit_val->val[i]); + + pval->ip = pdata[k++]; + for (j = 0; j < pval->opt_cnt; j++) { + pval->popt[j] = pdata[k]; + k += 2; + } + /*need to skip one*/ + k -= 1; + } + + if (IRIS_IF_LOGV()) { + IRIS_LOGE("ip_cnt = %0x", pinit_val->ip_cnt); + for (i = 0; i < pinit_val->ip_cnt; i++) { + char ptr[256]; + int32_t len = 0; + int32_t sum = 256; + struct iris_pq_ipopt_val *pval = &(pinit_val->val[i]); + + snprintf(ptr, sum, "ip is %0x opt is ", pval->ip); + for (j = 0; j < pval->opt_cnt; j++) { + len = strlen(ptr); + sum -= len; + snprintf(ptr + len, sum, "%0x ", pval->popt[j]); + } + IRIS_LOGE("%s", ptr); + } + } + + return rc; +} + +void iris_cm_setting_switch(bool dual) +{ + bool skiplast = 0; + int len; + struct iris_update_ipopt popt[IP_OPT_MAX]; + bool is_ulps_enable = 0; + uint8_t path = iris_pq_update_path; + struct quality_setting *pqlt_cur_setting = &iris_setting.quality_cur; + uint32_t *payload = NULL; + u32 pwil_datapath; + u32 cm_csc = 0x40; + // FIXME: WA for old pxlw-dtsi + // u32 pwil_csc = dual ? 0x95 : 0x96; + u32 pwil_csc = 0x95; + + if (pqlt_cur_setting->pq_setting.readingmode != 0) + cm_csc = 0x41; + switch (pqlt_cur_setting->pq_setting.sdr2hdr) { + case HDR10In_ICtCp: + case HDR10In_YCbCr: + case ICtCpIn_YCbCr: + cm_csc = 0x45; + break; + case SDR709_2_709: + /*TODOS*/ + break; + case SDR709_2_p3: + cm_csc = 0x46; + break; + case SDR709_2_2020: + /*TODOS*/ + break; + default: + break; + } + // FIXME: WA for old pxlw-dtsi + // if (!dual) + // cm_csc += 8; + iris_init_ipopt_ip(popt, IP_OPT_MAX); + len = iris_capture_disable_pq(popt, &skiplast); + + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_CM, cm_csc, skiplast); + len = iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, pwil_csc, skiplast); + + payload = iris_get_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 2); + pwil_datapath = payload[2] & ~0x00800000;// blending before PP + if (dual) + pwil_datapath |= 0x00800000; // blending after PP + iris_set_ipopt_payload_data(IRIS_IP_PWIL, 0xF1, 4, pwil_datapath); + iris_update_ip_opt(popt, IP_OPT_MAX, IRIS_IP_PWIL, 0xF1, 0x01); + + len = iris_capture_enable_pq(popt, len); + + is_ulps_enable = iris_disable_ulps(path); + iris_update_pq_opt(popt, len, path); + iris_enable_ulps(path, is_ulps_enable); +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_pq.h b/techpack/display/msm/dsi/iris/dsi_iris5_pq.h new file mode 100755 index 000000000000..825d670798df --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_pq.h @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRIS_PQ_H_ +#define _DSI_IRIS_PQ_H_ + + +enum { + IRIS_LCE_GRAPHIC = 0x00, + IRIS_LCE_VIDEO, +}; + +enum { + IRIS_COLOR_TEMP_OFF = 0x00, + IRIS_COLOR_TEMP_MANUL, + IRIS_COLOR_TEMP_AUTO, +}; + +enum { + IRIS_MAGENTA_GAIN_TYPE = 0, + IRIS_RED_GAIN_TYPE, + IRIS_YELLOW_GAIN_TYPE, + IRIS_GREEN_GAIN_TYPE, + IRIS_BLUE_GAIN_TYPE, + IRIS_CYAN_GAIN_TYPE, +}; + +#define IP_OPT_MAX 20 + +void iris_set_skip_dma(bool skip); + +void iris_pq_parameter_init(void); + +void iris_peaking_level_set(u32 level); + +void iris_cm_6axis_level_set(u32 level); + +void iris_cm_csc_level_set(u32 csc_ip, u32 *csc_value); + +void iris_cm_ftc_enable_set(u32 level); + +void iris_scurve_enable_set(u32 level); + +void iris_cm_colortemp_mode_set(u32 mode); + +void iris_cm_color_temp_set(void); + +u32 iris_cm_ratio_set_for_iic(void); + +void iris_cm_color_gamut_pre_set(u32 source_switch); + +void iris_cm_color_gamut_pre_clear(void); + +void iris_cm_color_gamut_set(u32 level); + +void iris_dpp_gamma_set(void); + +void iris_lce_mode_set(u32 mode); + +void iris_lce_level_set(u32 level); + +void iris_lce_graphic_det_set(bool enable); + +void iris_lce_al_set(bool enable); + +void iris_lce_demo_window_set(u32 vsize, u32 hsize, u8 inwnd); + +void iris_dbc_level_set(u32 level); + +void iris_pwm_freq_set(u32 value); + +void iris_pwm_enable_set(bool enable); + +void iris_dbc_bl_user_set(u32 value); + +void iris_dbc_led0d_gain_set(u32 value); + +void iris_reading_mode_set(u32 level); + +void iris_lce_lux_set(void); +void iris_ambient_light_lut_set(u32 lut_offset); +u32 iris_sdr2hdr_lut2ctl_get(void); +void iris_sdr2hdr_lut2ctl_set(u32 value); +void iris_maxcll_lut_set(u32 lutpos); +u32 iris_sdr2hdr_lutyctl_get(void); +void iris_sdr2hdr_lutyctl_set(u32 value); + +void iris_dbclce_datapath_set(bool bEn); + +void iris_dbclce_power_set(bool bEn); + +void iris_dbc_compenk_set(u8 lut_table_index); +void iris_sdr2hdr_level_set(u32 level); +void iris_pwil_sdr2hdr_resolution_set(bool enter_frc_mode); +void iris_panel_nits_set(u32 bl_ratio, bool bSystemRestore, int level); +void iris_scaler_filter_update(u8 scaler_type, u32 level); + +void iris_peaking_idle_clk_enable(bool enable); + +void iris_cm_6axis_seperate_gain(u8 gain_type, u32 value); + +void iris_init_ipopt_ip(struct iris_update_ipopt *ipopt, int len); +void iris_hdr_csc_prepare(void); +void iris_hdr_csc_complete(int step); +void iris_hdr_csc_frame_ready(void); +uint32_t iris_frc_variable_set(int frc_var_disp); +void iris_frc_force_repeat(bool enable); +void iris_pwil_frc_pt_set(int frc_pt_switch_on); +void iris_pwil_frc_ratio_set(int out_fps_ratio, int in_fps_ratio); +void iris_pwil_frc_video_ctrl2_set(int mvc_0_1_phase); +void iris_scaler_filter_ratio_get(void); +void iris_pwil_cmd_disp_mode_set(bool cmd_disp_on); +void iris_psf_mif_efifo_set(u8 mode, bool osd_enable); +void iris_psf_mif_dyn_addr_set(bool dyn_adrr_enable); +void iris_ms_pwil_dma_update(struct iris_mspwil_parameter *par); +void iris_dtg_frame_rate_set(u32 framerate); + +int32_t iris_update_ip_opt( + struct iris_update_ipopt *popt, int len, uint8_t ip, + uint8_t opt_id, uint8_t skip_last); + +int iris_dbgfs_pq_init(struct dsi_display *display); + +u8 iris_get_dbc_lut_index(void); + +struct iris_setting_info *iris_get_setting(void); + +void iris_set_yuv_input(bool val); + +void iris_set_HDR10_YCoCg(bool val); + +bool iris_get_debug_cap(void); + +void iris_set_debug_cap(bool val); + +void iris_set_sdr2hdr_mode(u8 val); + +void iris_quality_setting_off(void); + +struct msmfb_iris_ambient_info *iris_get_ambient_lut(void); + +struct msmfb_iris_maxcll_info *iris_get_maxcll_info(void); + +void iris_scaler_gamma_enable(bool lightup_en, u32 level); + +void iris_dom_set(int mode); + +void iris_brightness_level_set(u32 *value); + +int32_t iris_parse_color_temp_range(struct device_node *np, struct iris_cfg *pcfg); + +int32_t iris_parse_default_pq_param(struct device_node *np, struct iris_cfg *pcfg); + +void iris_cm_setting_switch(bool dual); +#endif // _DSI_IRIS_PQ_H_ diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.c b/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.c new file mode 100755 index 000000000000..9661e9bb1b73 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <dsi_drm.h> +#include "dsi_panel.h" +#include "dsi_iris5.h" +#include "dsi_iris5_api.h" +#include "dsi_iris5_lightup.h" +#include "dsi_iris5_lightup_ocp.h" +#include "dsi_iris5_mode_switch.h" +#include "dsi_iris5_lp.h" +#include "dsi_iris5_log.h" + + +enum { + SWITCH_ABYP_TO_ABYP = 0, + SWITCH_ABYP_TO_PT, + SWITCH_PT_TO_ABYP, + SWITCH_PT_TO_PT, + SWITCH_NONE, +}; + +#define SWITCH_CASE(case)[SWITCH_##case] = #case +static const char * const switch_case_name[] = { + SWITCH_CASE(ABYP_TO_ABYP), + SWITCH_CASE(ABYP_TO_PT), + SWITCH_CASE(PT_TO_ABYP), + SWITCH_CASE(PT_TO_PT), + SWITCH_CASE(NONE), +}; +#undef SWITCH_CASE + +void iris_init_timing_switch(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + pcfg->switch_case = SWITCH_ABYP_TO_ABYP; +} + +static int32_t _iris_parse_timing_switch_seq( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + const uint8_t *key = "pxlw,iris-timing-switch-sequence"; + + rc = iris_parse_optional_seq(np, key, &pcfg->timing_switch_seq); + if (rc != 0) { + IRIS_LOGE("%s(), failed to parse %s seq", __func__, key); + return rc; + } + + key = "pxlw,iris-timing-switch-sequence-1"; + rc = iris_parse_optional_seq(np, key, &pcfg->timing_switch_seq_1); + if (rc != 0) { + IRIS_LOGE("%s(), failed to parse %s seq", __func__, key); + return rc; + } + + return rc; +} + +int32_t iris_parse_timing_switch_info( + struct device_node *np, struct iris_cfg *pcfg) +{ + int32_t rc = 0; + + rc = iris_parse_dtsi_cmd(np, IRIS_DTSI1_PIP_IDX); + if (rc) + IRIS_LOGI("%s, [optional] have not cmds list 1", __func__); + + rc = _iris_parse_timing_switch_seq(np, pcfg); + if (rc) + IRIS_LOGI("%s, [optional] have not timing switch sequence", __func__); + + return 0; +} + +void iris_send_timing_switch_pkt(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + struct iris_ctrl_seq *pseq = &pcfg->timing_switch_seq; + struct iris_ctrl_opt *arr = NULL; + int refresh_rate = pcfg->panel->cur_mode->timing.refresh_rate; + int v_active = pcfg->panel->cur_mode->timing.v_active; + + if ((refresh_rate == HIGH_FREQ) && (v_active == FHD_H)) + pseq = &pcfg->timing_switch_seq_1; + + IRIS_LOGI("%s, cmd list index: %d, v res: %d, fps: %d", + __func__, pcfg->cmd_list_index, v_active, refresh_rate); + + if (pseq == NULL) { + IRIS_LOGE("%s(), seq is NULL", __func__); + return; + } + arr = pseq->ctrl_opt; + + iris_send_assembled_pkt(arr, pseq->cnt); + udelay(100); +} + +static uint32_t _iris_switch_case(const u32 refresh_rate, const u32 frame_height) +{ + struct iris_cfg *pcfg = iris_get_cfg_by_index(DSI_PRIMARY); + bool cur_pt_mode = (pcfg->abypss_ctrl.abypass_mode == PASS_THROUGH_MODE); + u32 switch_mode = SWITCH_ABYP_TO_ABYP; + + IRIS_LOGD("%s(), refersh rate %u, frame height %u, iris current mode '%s'", + __func__, refresh_rate, frame_height, cur_pt_mode ? "PT" : "ABYP"); + + if (frame_height == QHD_H) { + pcfg->cmd_list_index = IRIS_DTSI0_PIP_IDX; + if (cur_pt_mode) + switch_mode = SWITCH_PT_TO_ABYP; + } + + if (frame_height == FHD_H) { + pcfg->cmd_list_index = IRIS_DTSI1_PIP_IDX; + if (cur_pt_mode) { + if (pcfg->cur_v_active == QHD_H) + switch_mode = SWITCH_PT_TO_ABYP; + else + switch_mode = SWITCH_PT_TO_PT; + } + } + + return switch_mode; +} + +bool iris_is_resolution_switched(struct dsi_mode_info *mode_info) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + + IRIS_LOGD("%s(), switch resolution from %ux%u to %ux%u", __func__, + pcfg->cur_h_active, pcfg->cur_v_active, + mode_info->h_active, mode_info->v_active); + + if (pcfg->cur_h_active != mode_info->h_active + || pcfg->cur_v_active != mode_info->v_active) { + pcfg->cur_h_active = mode_info->h_active; + pcfg->cur_v_active = mode_info->v_active; + + return true; + } + + return false; +} + +static void _iris_switch_framerate(void) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + u32 framerate = pcfg->panel->cur_mode->timing.refresh_rate; + bool high = false; + + if ((framerate == HIGH_FREQ) + && (pcfg->panel->cur_mode->timing.v_active == FHD_H)) + high = true; + + iris_send_ipopt_cmds(IRIS_IP_SYS, high ? 0xA1:0xA0); + udelay(100); + iris_send_ipopt_cmds(IRIS_IP_RX, high ? 0xE1:0xE0); + iris_send_ipopt_cmds(IRIS_IP_TX, high ? 0x4:0x0); + iris_set_out_frame_rate(framerate); + iris_send_ipopt_cmds(IRIS_IP_RX, high ? 0xF2:0xF1); +#if defined(PXLW_IRIS_DUAL) + iris_send_ipopt_cmds(IRIS_IP_RX_2, high ? 0xF2:0xF1); + iris_send_ipopt_cmds(IRIS_IP_BLEND, high ? 0xF1:0xF0); +#endif + udelay(2000); //delay 2ms +} + +int iris_post_switch(struct dsi_panel *panel, + struct dsi_panel_cmd_set *switch_cmds, + struct dsi_mode_info *mode_info) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + int lightup_opt = iris_lightup_opt_get(); + u32 refresh_rate = mode_info->refresh_rate; + u32 frame_width = mode_info->h_active; + u32 frame_height = mode_info->v_active; + u32 switch_case = _iris_switch_case(refresh_rate, frame_height); + + IRIS_LOGI("%s(), post switch to %ux%u@%uHz, cmd list %u, switch case %s", + __func__, frame_width, frame_height, refresh_rate, + pcfg->cmd_list_index, switch_case_name[switch_case]); + + pcfg->switch_case = switch_case; + + if (switch_cmds == NULL) + return 0; + + if (lightup_opt & 0x8) { + rc = iris_dsi_send_cmds(panel, switch_cmds->cmds, switch_cmds->count, switch_cmds->state); + IRIS_LOGI("%s(), post switch Force ABYP", __func__); + return 0; + } + + if (iris_get_abyp_mode(panel) == PASS_THROUGH_MODE) + rc = iris_pt_send_panel_cmd(panel, &(panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_POST_TIMING_SWITCH])); + else + rc = iris_dsi_send_cmds(panel, switch_cmds->cmds, switch_cmds->count, switch_cmds->state); + + IRIS_LOGD("%s(), return %d", __func__, rc); + return 0; +} + +int iris_switch(struct dsi_panel *panel, + struct dsi_panel_cmd_set *switch_cmds, + struct dsi_mode_info *mode_info) +{ + int rc = 0; + struct iris_cfg *pcfg = iris_get_cfg(); + int lightup_opt = iris_lightup_opt_get(); + u32 refresh_rate = mode_info->refresh_rate; + u32 switch_case = pcfg->switch_case; + ktime_t ktime = 0; + + IRIS_LOGD("%s(%d)", __func__, __LINE__); + + pcfg->panel_te = refresh_rate; + pcfg->ap_te = refresh_rate; + pcfg->next_fps_for_iris = refresh_rate; + + if (IRIS_IF_LOGI()) + ktime = ktime_get(); + + if (lightup_opt & 0x8) { + rc = iris_dsi_send_cmds(panel, switch_cmds->cmds, switch_cmds->count, switch_cmds->state); + IRIS_LOGI("%s(), switch between ABYP and ABYP, total cost '%d us'", + __func__, + (u32)(ktime_to_us(ktime_get()) - ktime_to_us(ktime))); + IRIS_LOGW("%s(), force ABYP switch.", __func__); + return rc; + } + + if (switch_case == SWITCH_ABYP_TO_ABYP) + rc = iris_dsi_send_cmds(panel, switch_cmds->cmds, switch_cmds->count, switch_cmds->state); + + if (switch_case == SWITCH_PT_TO_PT) { + rc = iris_pt_send_panel_cmd(panel, switch_cmds); + _iris_switch_framerate(); + } + + if (switch_case == SWITCH_PT_TO_ABYP) { + iris_abypass_switch_proc(pcfg->display, ANALOG_BYPASS_MODE, false, true); + rc = iris_dsi_send_cmds(panel, switch_cmds->cmds, switch_cmds->count, switch_cmds->state); + } + + // Update panel timing + iris_is_resolution_switched(mode_info); + + IRIS_LOGI("%s(), return %d, total cost '%d us'", + __func__, + rc, (u32)(ktime_to_us(ktime_get()) - ktime_to_us(ktime))); + + return 0; +} + +uint32_t iris_get_cont_type_with_timing_switch(struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = iris_get_cfg(); + uint32_t type = IRIS_CONT_SPLASH_NONE; + uint32_t switch_case = SWITCH_NONE; + + if (pcfg->valid >= PARAM_PARSED) + switch_case = _iris_switch_case( + panel->cur_mode->timing.refresh_rate, + panel->cur_mode->timing.v_active); + + IRIS_LOGI("%s(), switch case: %s, rate: %d, v: %d", + __func__, + switch_case_name[switch_case], + panel->cur_mode->timing.refresh_rate, + panel->cur_mode->timing.v_active); + + switch (switch_case) { + case SWITCH_PT_TO_PT: + type = IRIS_CONT_SPLASH_LK; + break; + case SWITCH_ABYP_TO_ABYP: + case SWITCH_ABYP_TO_PT: + type = IRIS_CONT_SPLASH_BYPASS_PRELOAD; + break; + case SWITCH_PT_TO_ABYP: + // This case does not happen + default: + type = IRIS_CONT_SPLASH_NONE; + break; + } + + return type; +} diff --git a/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.h b/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.h new file mode 100755 index 000000000000..fdef0b613a9d --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_iris5_timing_switch.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef __DSI_IRIS_TIMING_SWITCH__ +#define __DSI_IRIS_TIMING_SWITCH__ + + +void iris_init_timing_switch(void); +int32_t iris_parse_timing_switch_info(struct device_node *np, + struct iris_cfg *pcfg); +void iris_send_timing_switch_pkt(void); +bool iris_is_resolution_switched(struct dsi_mode_info *mode_info); +uint32_t iris_get_cont_type_with_timing_switch(struct dsi_panel *panel); + +#endif //__DSI_IRIS_TIMING_SWITCH__ diff --git a/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.c b/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.c new file mode 100755 index 000000000000..24e766c7f9ad --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <drm/drm_mipi_dsi.h> +#include <dsi_drm.h> +#include <sde_trace.h> + +#include "dsi_iris5_api.h" +#include "dsi_iris5.h" +#include "dsi_iris5_lightup.h" +#include "dsi_irissoft_ioctl.h" + +static int gcfg_index = 0; +static struct iris_cfg gcfg[IRIS_CFG_NUM] = {}; + +int iris_wait_vsync() +{ + struct iris_cfg *pcfg = &gcfg[gcfg_index]; + struct drm_encoder *drm_enc; + struct drm_crtc *crtc; + + // iris_get_drm_encoder_handle() + if (pcfg->display->bridge == NULL) + return -ENOLINK; + drm_enc = pcfg->display->bridge->base.encoder; + if (!drm_enc || !drm_enc->crtc) + return -ENOLINK; + + crtc = drm_enc->crtc; + drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); + + return 0; +} + +int iris_set_pending_panel_brightness(int32_t pending, int32_t delay, int32_t level) +{ + struct iris_cfg *pcfg = &gcfg[gcfg_index]; + + DSI_INFO("IRIS_LOG set pending panel %d,%d,%d", pending, delay, level); + pcfg->panel_pending = pending; + pcfg->panel_delay = delay; + pcfg->panel_level = level; + + return 0; +} + +int iris_sync_panel_brightness(int32_t step, void *phys_enc) +{ + struct sde_encoder_phys *phys_encoder = phys_enc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display = NULL; + struct iris_cfg *pcfg; + int rc = 0; + + if (phys_encoder == NULL) + return -EFAULT; + if (phys_encoder->connector == NULL) + return -EFAULT; + + c_conn = to_sde_connector(phys_encoder->connector); + if (c_conn == NULL) + return -EFAULT; + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + display = c_conn->display; + if (display == NULL) + return -EFAULT; + + pcfg = &gcfg[gcfg_index]; + + if (pcfg->panel_pending == step) { + DSI_INFO("IRIS_LOG sync pending panel %d %d,%d,%d", step, pcfg->panel_pending, pcfg->panel_delay, pcfg->panel_level); + SDE_ATRACE_BEGIN("sync_panel_brightness"); + if (step <= 2) { + rc = c_conn->ops.set_backlight(&c_conn->base, + display, pcfg->panel_level); + usleep_range(pcfg->panel_delay, pcfg->panel_delay); + } else { + usleep_range(pcfg->panel_delay, pcfg->panel_delay); + rc = c_conn->ops.set_backlight(&c_conn->base, + display, pcfg->panel_level); + } + if (c_conn->bl_device) + c_conn->bl_device->props.brightness = pcfg->panel_level; + pcfg->panel_pending = 0; + SDE_ATRACE_END("sync_panel_brightness"); + } + + return rc; +} + +int iris_configure(u32 display, u32 type, u32 value) +{ + if (type >= IRIS_CONFIG_TYPE_MAX) + return -1; + /* FIXME + if (mfd->panel_power_state == MDSS_PANEL_POWER_OFF) + return -1; + */ + + switch (type) { + case IRIS_WAIT_VSYNC: + return iris_wait_vsync(); + default: + break; + } + + return 0; +} + +int iris_configure_t(uint32_t display, u32 type, void __user *argp) +{ + int ret = -1; + uint32_t value = 0; + + ret = copy_from_user(&value, argp, sizeof(uint32_t)); + if (ret) { + DSI_ERR("can not copy from user"); + return -EPERM; + } + + ret = iris_configure(display, type, value); + return ret; +} + +int iris_configure_ex(u32 display, u32 type, u32 count, u32 *values) +{ + if (type >= IRIS_CONFIG_TYPE_MAX) + return -1; + + switch (type) { + case IRIS_WAIT_VSYNC: + if (count > 2) + iris_set_pending_panel_brightness(values[0], values[1], values[2]); + break; + default: + break; + } + + return 0; +} + +int iris_configure_ex_t(uint32_t display, uint32_t type, + uint32_t count, void __user *values) +{ + int ret = -1; + uint32_t *val = NULL; + + val = kmalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val) { + DSI_ERR("can not kmalloc space"); + return -ENOSPC; + } + ret = copy_from_user(val, values, sizeof(uint32_t) * count); + if (ret) { + DSI_ERR("can not copy from user"); + kfree(val); + return -EPERM; + } + ret = iris_configure_ex(display, type, count, val); + kfree(val); + return ret; +} + +void iris_init(struct dsi_display *display, struct dsi_panel *panel) +{ + struct iris_cfg *pcfg = &gcfg[gcfg_index]; + + DSI_INFO("IRIS_LOG %s:%d", __func__, __LINE__); + pcfg->display = display; + pcfg->panel = panel; + pcfg->valid = 1; /* empty */ +} + +int iris_operate_tool(struct msm_iris_operate_value *argp) +{ + return -EINVAL; +} + +int iris_operate_conf(struct msm_iris_operate_value *argp) +{ + int ret = -1; + uint32_t parent_type = 0; + uint32_t child_type = 0; + uint32_t display_type = 0; + struct iris_cfg *pcfg = NULL; + + parent_type = argp->type & 0xff; + child_type = (argp->type >> 8) & 0xff; + display_type = (argp->type >> 16) & 0xff; + pcfg = &gcfg[gcfg_index]; + if (pcfg == NULL || pcfg->valid < 1) { + DSI_ERR("Target display does not exist!"); + return -EPERM; + } + + switch (parent_type) { + case IRIS_OPRT_CONFIGURE: + mutex_lock(&pcfg->panel->panel_lock); + ret = iris_configure_t(display_type, child_type, argp->values); + mutex_unlock(&pcfg->panel->panel_lock); + break; + case IRIS_OPRT_CONFIGURE_NEW: + mutex_lock(&pcfg->panel->panel_lock); + ret = iris_configure_ex_t(display_type, child_type, argp->count, argp->values); + mutex_unlock(&pcfg->panel->panel_lock); + break; + default: + ret = 0; + break; + } + + return ret; +} diff --git a/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.h b/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.h new file mode 100755 index 000000000000..1fc8eaadfdc7 --- /dev/null +++ b/techpack/display/msm/dsi/iris/dsi_irissoft_ioctl.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#ifndef _DSI_IRISSOFT_IOCTL_H_ +#define _DSI_IRISSOFT_IOCTL_H_ + +int iris_configure(u32 display, u32 type, u32 value); + +#endif // _DSI_IRISSOFT_IOCTL_H_ diff --git a/techpack/display/msm/dsi/iris/msm_iris5_extended.c b/techpack/display/msm/dsi/iris/msm_iris5_extended.c new file mode 100755 index 000000000000..bab63d5922c9 --- /dev/null +++ b/techpack/display/msm/dsi/iris/msm_iris5_extended.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include "msm_drv.h" +#include "msm_kms.h" + + +int msm_ioctl_iris_operate_conf(struct drm_device *dev, void *data, + struct drm_file *file) +{ + int ret = -EINVAL; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + ret = kms->funcs->iris_operate(kms, DRM_MSM_IRIS_OPERATE_CONF, data); + return ret; +} + +int msm_ioctl_iris_operate_tool(struct drm_device *dev, void *data, + struct drm_file *file) +{ + int ret = -EINVAL; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + ret = kms->funcs->iris_operate(kms, DRM_MSM_IRIS_OPERATE_TOOL, data); + return ret; +} diff --git a/techpack/display/msm/dsi/iris/sde_iris5_extended.c b/techpack/display/msm/dsi/iris/sde_iris5_extended.c new file mode 100755 index 000000000000..4d91031479e4 --- /dev/null +++ b/techpack/display/msm/dsi/iris/sde_iris5_extended.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ +#include <sde_hw_mdss.h> +#include <sde_hw_sspp.h> +#include "dsi_iris5_api.h" +#include "dsi_iris5.h" +#include "dsi_iris5_log.h" + + +void iris_sde_plane_setup_csc(void *csc_ptr) +{ + static const struct sde_csc_cfg hdrYUV = { + { + 0x00010000, 0x00000000, 0x00000000, + 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00010000, + }, + { 0x0, 0x0, 0x0,}, + { 0x0, 0x0, 0x0,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, + }; + static const struct sde_csc_cfg hdrRGB10 = { + /* S15.16 format */ + { + 0x00012A15, 0x00000000, 0x0001ADBE, + 0x00012A15, 0xFFFFD00B, 0xFFFF597E, + 0x00012A15, 0x0002244B, 0x00000000, + }, + /* signed bias */ + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, + }; + + if (!iris_is_chip_supported()) + return; + + if (iris_get_hdr_enable() == 1) + csc_ptr = (void *)&hdrYUV; + else if (iris_get_hdr_enable() == 2) + csc_ptr = (void *)&hdrRGB10; + + return; +} + + +int iris_sde_kms_iris_operate(struct msm_kms *kms, + u32 operate_type, struct msm_iris_operate_value *operate_value) +{ + int ret = -EINVAL; + + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return 0; + + if (operate_type == DRM_MSM_IRIS_OPERATE_CONF) { + ret = iris_operate_conf(operate_value); + } else if (operate_type == DRM_MSM_IRIS_OPERATE_TOOL) { + ret = iris_operate_tool(operate_value); + } + + return ret; +} + + +void iris_sde_update_dither_depth_map(uint32_t *map) +{ + if (!iris_is_chip_supported()) + return; + + map[5] = 1; + map[6] = 2; + map[7] = 3; + map[8] = 2; +} + + +void iris_sde_prepare_for_kickoff(uint32_t num_phys_encs, void *phys_enc) +{ + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return; + + if (num_phys_encs == 0) + return; + + if (iris_is_chip_supported()) + iris_prepare_for_kickoff(phys_enc); + iris_sync_panel_brightness(1, phys_enc); +} + +void iris_sde_encoder_kickoff(uint32_t num_phys_encs, void *phys_enc) +{ + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return; + + if (num_phys_encs == 0) + return; + + if (iris_is_chip_supported()) + iris_kickoff(phys_enc); + iris_sync_panel_brightness(2, phys_enc); +} + +void iris_sde_encoder_sync_panel_brightness(uint32_t num_phys_encs, void *phys_enc) +{ + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return; + + if (num_phys_encs == 0) + return; + + iris_sync_panel_brightness(3, phys_enc); +} + +void iris_sde_encoder_wait_for_event(uint32_t num_phys_encs, void *phys_enc, + uint32_t event) +{ + if (!iris_is_chip_supported() && !iris_is_softiris_supported()) + return; + + if (num_phys_encs == 0) + return; + + if (event != MSM_ENC_COMMIT_DONE) + return; + + iris_sync_panel_brightness(4, phys_enc); +} + +#if defined(PXLW_IRIS_DUAL) +#define CSC_10BIT_OFFSET 4 +#define DGM_CSC_MATRIX_SHIFT 0 + +extern int iris_sspp_subblk_offset(struct sde_hw_pipe *ctx, int s_id, u32 *idx); + +void iris_sde_hw_sspp_setup_csc_v2(void *pctx, const void *pfmt, void *pdata) +{ + u32 idx = 0; + u32 op_mode = 0; + u32 clamp_shift = 0; + u32 val; + u32 op_mode_off = 0; + bool csc10 = false; + const struct sde_sspp_sub_blks *sblk; + struct sde_hw_pipe *ctx = pctx; + const struct sde_format *fmt = pfmt; + struct sde_csc_cfg *data = pdata; + + if (!iris_is_dual_supported()) + return; + + if (!ctx || !ctx->cap || !ctx->cap->sblk) + return; + + if (SDE_FORMAT_IS_YUV(fmt)) + return; + + if (!iris_is_chip_supported()) + return; + + sblk = ctx->cap->sblk; + if (iris_sspp_subblk_offset(ctx, SDE_SSPP_CSC_10BIT, &idx)) + return; + + op_mode_off = idx; + if (test_bit(SDE_SSPP_CSC_10BIT, &ctx->cap->features)) { + idx += CSC_10BIT_OFFSET; + csc10 = true; + } + clamp_shift = csc10 ? 16 : 8; + if (data && !SDE_FORMAT_IS_YUV(fmt)) { + op_mode |= BIT(0); + sde_hw_csc_matrix_coeff_setup(&ctx->hw, + idx, data, DGM_CSC_MATRIX_SHIFT); + /* Pre clamp */ + val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; + SDE_REG_WRITE(&ctx->hw, idx + 0x14, val); + val = (data->csc_pre_lv[2] << clamp_shift) | data->csc_pre_lv[3]; + SDE_REG_WRITE(&ctx->hw, idx + 0x18, val); + val = (data->csc_pre_lv[4] << clamp_shift) | data->csc_pre_lv[5]; + SDE_REG_WRITE(&ctx->hw, idx + 0x1c, val); + + /* Post clamp */ + val = (data->csc_post_lv[0] << clamp_shift) | data->csc_post_lv[1]; + SDE_REG_WRITE(&ctx->hw, idx + 0x20, val); + val = (data->csc_post_lv[2] << clamp_shift) | data->csc_post_lv[3]; + SDE_REG_WRITE(&ctx->hw, idx + 0x24, val); + val = (data->csc_post_lv[4] << clamp_shift) | data->csc_post_lv[5]; + SDE_REG_WRITE(&ctx->hw, idx + 0x28, val); + + /* Pre-Bias */ + SDE_REG_WRITE(&ctx->hw, idx + 0x2c, data->csc_pre_bv[0]); + SDE_REG_WRITE(&ctx->hw, idx + 0x30, data->csc_pre_bv[1]); + SDE_REG_WRITE(&ctx->hw, idx + 0x34, data->csc_pre_bv[2]); + + /* Post-Bias */ + SDE_REG_WRITE(&ctx->hw, idx + 0x38, data->csc_post_bv[0]); + SDE_REG_WRITE(&ctx->hw, idx + 0x3c, data->csc_post_bv[1]); + SDE_REG_WRITE(&ctx->hw, idx + 0x40, data->csc_post_bv[2]); + } + IRIS_LOGD("%s(), name:%s offset:%x ctx->idx:%x op_mode:%x", + __func__, sblk->csc_blk.name, idx, ctx->idx, op_mode); + SDE_REG_WRITE(&ctx->hw, op_mode_off, op_mode); + wmb(); +} +#endif diff --git a/techpack/display/msm/msm_atomic.c b/techpack/display/msm/msm_atomic.c new file mode 100755 index 000000000000..1967aa18dab6 --- /dev/null +++ b/techpack/display/msm/msm_atomic.c @@ -0,0 +1,858 @@ +/* + * 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_atomic_state *state, + struct drm_crtc_state *crtc_state, bool enable) +{ + struct drm_connector *connector = NULL; + struct drm_connector_state *conn_state = NULL; + int i = 0; + int conn_cnt = 0; + + 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 (MULTIPLE_CONN_DETECTED(conn_cnt)) + 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(&old_conn_state->crtc->state->mode)) + return true; + + if (msm_is_mode_seamless_vrr( + &old_conn_state->crtc->state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dyn_clk( + &old_conn_state->crtc->state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dms( + &old_conn_state->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 bool +msm_disable_outputs_for_clone_conn(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *crtc = NULL; + int i; + bool clone_state = false; + + for_each_old_connector_in_state(old_state, connector, + old_conn_state, i) { + + 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 || + !old_conn_state->crtc->state->connectors_changed || + (!_msm_seamless_for_conn(connector, old_conn_state, + false) && (connector->connector_type != + DRM_MODE_CONNECTOR_VIRTUAL))) + return false; + + if (crtc) + clone_state = (crtc == old_conn_state->crtc) + ? true : false; + + crtc = old_conn_state->crtc; + } + + return clone_state; +} + +static void +msm_disable_connector_outputs(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + int i; + + SDE_ATRACE_BEGIN("msm_disable_connector"); + 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); + } + SDE_ATRACE_END("msm_disable_connector"); +} + +static void +msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + SDE_ATRACE_BEGIN("msm_disable"); + if (!msm_disable_outputs_for_clone_conn(dev, old_state)) + msm_disable_connector_outputs(dev, old_state); + + 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(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(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); + + if (msm_disable_outputs_for_clone_conn(dev, state)) + msm_disable_connector_outputs(dev, 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)); + } + + /* + * 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 100755 index 000000000000..185333f0f044 --- /dev/null +++ b/techpack/display/msm/msm_drv.c @@ -0,0 +1,2096 @@ +/* + * 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" +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) +#include "dsi/iris/dsi_iris5_api.h" +#endif + +/* + * 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))) + 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), +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + DRM_IOCTL_DEF_DRV(MSM_IRIS_OPERATE_CONF, msm_ioctl_iris_operate_conf, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_IRIS_OPERATE_TOOL, msm_ioctl_iris_operate_tool, DRM_UNLOCKED|DRM_RENDER_ALLOW), +#endif +}; + +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 100755 index 000000000000..a8d62ebd3a44 --- /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, + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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 100755 index 000000000000..f5ddd139e57c --- /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 100755 index 000000000000..78f804c12ef2 --- /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 100755 index 000000000000..a38ccc204f66 --- /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 100755 index 000000000000..9b9290e03b62 --- /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 100755 index 000000000000..d40f0fd502d1 --- /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 100755 index 000000000000..2240f774dde6 --- /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 100755 index 000000000000..2a90aa4caec0 --- /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 100755 index 000000000000..97e76f41f257 --- /dev/null +++ b/techpack/display/msm/msm_kms.h @@ -0,0 +1,245 @@ +/* + * 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_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); + /* 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); +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + int (*iris_operate)(struct msm_kms *kms, u32 operate_type, struct msm_iris_operate_value *operate_value); +#endif +}; + +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 100755 index 000000000000..ee6cbcd58079 --- /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 100755 index 000000000000..f6cb9c56d0c6 --- /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 100755 index 000000000000..d7c9eb0f8475 --- /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 100755 index 000000000000..6069aaaa5003 --- /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 100755 index 000000000000..824103055b19 --- /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 100755 index 000000000000..7d99d4faeaba --- /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 100755 index 000000000000..6777d0e4c31b --- /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 100755 index 000000000000..0b831977d740 --- /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 100755 index 000000000000..54567afd82c3 --- /dev/null +++ b/techpack/display/msm/sde/sde_connector.c @@ -0,0 +1,3085 @@ +// 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); +} + +extern void dsi_display_change_err_flag_irq_status(struct dsi_display *display, + bool enable); +void sde_connector_schedule_status_work(struct drm_connector *connector, + bool en) +{ + struct sde_connector *c_conn; + struct msm_display_info info; + struct dsi_display *dsi_display; + c_conn = to_sde_connector(connector); + if (!c_conn) + return; + + dsi_display = (struct dsi_display *)c_conn->display; + + /* 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; + dsi_display_change_err_flag_irq_status(dsi_display, true); + } else { + /* Cancel any pending ESD status check */ + cancel_delayed_work_sync(&c_conn->status_work); + c_conn->esd_status_check = false; + dsi_display_change_err_flag_irq_status(dsi_display, 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; +} + +//xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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; +extern char dsi_panel_name; +extern u32 mode_fps; +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; + } + if (dsi_panel_name == 5) { + if (mode_fps == 120) + mdelay(9); + else + mdelay(17); + } + } + } + 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); + /*xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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; +} + +struct delayed_work *sde_esk_check_delayed_work; +EXPORT_SYMBOL(sde_esk_check_delayed_work); +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; + } + + sde_esk_check_delayed_work = &conn->status_work; + + 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; + + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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 100755 index 000000000000..9389f135109e --- /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 100755 index 000000000000..5ee1865be632 --- /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 100755 index 000000000000..ce27b20ee6c1 --- /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 100755 index 000000000000..3add93d9a61e --- /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 100755 index 000000000000..6f644b859222 --- /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 100755 index 000000000000..7acbfa07c3c4 --- /dev/null +++ b/techpack/display/msm/sde/sde_crtc.c @@ -0,0 +1,7226 @@ +/* + * 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" +//xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, add for fingerprint +#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]); + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, add for fingerprint + 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); + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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); + } +} + +//xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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, 233}, + {20, 228}, + {40, 219}, + {60, 211}, + {90, 203}, + {140, 191}, + {200, 179}, + {300, 168}, + {454, 149}, + {600, 133}, + {800, 115}, + {1000, 103}, + {1200, 87}, + {1600, 64}, + {2047, 43}, + {2047, 43}, +}; + +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) { + + if (enc->crtc == NULL) + SDE_ERROR("enc->crtc is null\n"); + + if (enc->crtc != crtc) + SDE_ERROR("enc->crtc unequal crtc\n"); + + 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) { + + if (enc->crtc == NULL) + SDE_ERROR("enc->crtc is null\n"); + + if (enc->crtc != crtc) + SDE_ERROR("enc->crtc unequal crtc\n"); + + 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; + if (mode_fps == 60 && dsi_panel_name == DSI_PANEL_SAMSUNG_S6E3HC2) + dim_backlight_pre = 1; + } else { + op_dimlayer_bl = 0; + } + } else { + op_dimlayer_bl = 0; + if (dim_backlight_pre) { + if (mode_fps == 60 && dsi_panel_name == DSI_PANEL_SAMSUNG_S6E3HC2) + 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){ + SDE_ATRACE_BEGIN("aod_layer_reset"); + pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + SDE_ATRACE_END("aod_layer_reset"); + } + } + } + } + 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); + + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, add for fingerprint + 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_ANA6705) { + for (i = 0; i < 21; i++) + brightness_alpha_lut[i] = brightness_alpha_lut_1[i]; + } else if (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6706) { + for (i = 0; i < 21; i++) + brightness_alpha_lut[i] = brightness_alpha_lut_2[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 100755 index 000000000000..7e58a6d48e8c --- /dev/null +++ b/techpack/display/msm/sde/sde_crtc.h @@ -0,0 +1,880 @@ +/* + * 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_S6E3HC2 0 +#define DSI_PANEL_SAMSUNG_S6E3FC2X01 1 +#define DSI_PANEL_SAMSUNG_SOFEF03F_M 2 +#define DSI_PANEL_SAMSUNG_ANA6705 3 +#define DSI_PANEL_SAMSUNG_ANA6706 4 + +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 100755 index 000000000000..692f3a68bee5 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder.c @@ -0,0 +1,6350 @@ +/* + * 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" + +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#elif defined(CONFIG_PXLW_SOFT_IRIS) +#include "iris/dsi_iris5_api.h" +#include "iris/dsi_iris5.h" +#endif +#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 DSI_PANEL_SAMSUNG_S6E3HC2 0 +#define DSI_PANEL_SAMSUNG_S6E3FC2X01 1 +extern char dsi_panel_name; +#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; +#if defined(CONFIG_PXLW_IRIS) + struct kthread_work disable_autorefresh_work; +#endif + 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); + + /* left primary encoder keep vote */ + if (sde_encoder_in_clone_mode(drm_enc)) { + SDE_EVT32(rsc_state, SDE_EVTLOG_FUNC_CASE1); + return 0; + } + + if ((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; + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, add for fingerprint + if (dsi_panel_name == DSI_PANEL_SAMSUNG_S6E3HC2) { + rsc_config->fps = 90; + } + else { + 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; +} + +/*kent.xie@MM.Display.LCD.Feature,2018-08-19 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) { + /*kent.xie@MM.Display.LCD.Feature,2018-08-19 force enable dither on Fingerprint scene */ + 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)); + + /*Kent.xie@MM.Display.LCD,2019-03-29 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); + +#if defined(CONFIG_PXLW_IRIS) + iris_sde_prepare_for_kickoff(sde_enc->num_phys_encs, + sde_enc->phys_encs[0]); + +#elif defined(CONFIG_PXLW_SOFT_IRIS) + if (sde_enc->num_phys_encs > 0) + iris_sync_panel_brightness(1, sde_enc->phys_encs[0]); +#endif + _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); + +#if defined(CONFIG_PXLW_IRIS) + iris_sde_encoder_kickoff(sde_enc->num_phys_encs, + sde_enc->phys_encs[0]); +#elif defined(CONFIG_PXLW_SOFT_IRIS) + if (sde_enc->num_phys_encs > 0) + iris_sync_panel_brightness(2, sde_enc->phys_encs[0]); +#endif + /* 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 defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + iris_sde_encoder_sync_panel_brightness(sde_enc->num_phys_encs, + sde_enc->phys_encs[0]); +#endif + + 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, +}; + +#if defined(CONFIG_PXLW_IRIS) +static void sde_encoder_disable_autorefresh_work_handler(struct kthread_work *work); +#endif +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); +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) + kthread_init_work(&sde_enc->disable_autorefresh_work, + sde_encoder_disable_autorefresh_work_handler); +#endif + + 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; + } + } +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + iris_sde_encoder_wait_for_event(sde_enc->num_phys_encs, + sde_enc->phys_encs[0], event); +#endif + + 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; +} + +#if defined(CONFIG_PXLW_IRIS) +void sde_encoder_rc_lock(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + mutex_lock(&sde_enc->rc_lock); +} + +void sde_encoder_rc_unlock(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + mutex_unlock(&sde_enc->rc_lock); +} + +void sde_encoder_disable_autorefresh_handler(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder parameters\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + if (!sde_enc->crtc) { + SDE_ERROR("invalid crtc"); + return; + } + + 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->disable_autorefresh_work); +} + +static void sde_encoder_disable_autorefresh_work_handler(struct kthread_work *work) +{ + // FIXME: add it in lightup.c + iris_inc_osd_irq_cnt(); +} + +bool sde_encoder_is_disabled(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + + sde_enc = to_sde_encoder_virt(drm_enc); + phys = sde_enc->phys_encs[0]; + return (phys->enable_state == SDE_ENC_DISABLED); +} +#endif diff --git a/techpack/display/msm/sde/sde_encoder.h b/techpack/display/msm/sde/sde_encoder.h new file mode 100755 index 000000000000..ea426448785b --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder.h @@ -0,0 +1,388 @@ +/* + * 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); + +#if defined(CONFIG_PXLW_IRIS) +/** + * sde_encoder_rc_lock - lock the sde encoder resource control. + * @drm_enc: Pointer to drm encoder structure + * @Return: void. + */ +void sde_encoder_rc_lock(struct drm_encoder *drm_enc); + +/** + * sde_encoder_rc_unlock - unlock the sde encoder resource control. + * @drm_enc: Pointer to drm encoder structure + * @Return: void. + */ +void sde_encoder_rc_unlock(struct drm_encoder *drm_enc); + +/** + * sde_encoder_disable_autorefresh - disable autorefresh + * @drm_enc: Pointer to drm encoder structure + * @Return: void. + */ +void sde_encoder_disable_autorefresh_handler(struct drm_encoder *drm_enc); + +/** + * sde_encoder_is_disabled - encoder is disabled + * @drm_enc: Pointer to drm encoder structure + * @Return: bool. + */ +bool sde_encoder_is_disabled(struct drm_encoder *drm_enc); +#endif +#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 100755 index 000000000000..8f35a8fa54ea --- /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 100755 index 000000000000..13ea41eee385 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys_cmd.c @@ -0,0 +1,2108 @@ +// 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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 +#if defined(PXLW_IRIS_DUAL) +/* decrease the polling time interval, reduce polling time */ +#define AUTOREFRESH_SEQ1_POLL_TIME (iris_is_dual_supported() ? 1000 : 2000) +#define AUTOREFRESH_SEQ2_POLL_TIME (iris_is_dual_supported() ? 1000 : 25000) +#else +#define AUTOREFRESH_SEQ1_POLL_TIME 2000 +#define AUTOREFRESH_SEQ2_POLL_TIME 25000 +#endif +#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; +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + if (iris_secondary_display_autorefresh(phys_enc)) + return 1; + } +#endif + + 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 defined(PXLW_IRIS_DUAL) + if (!(autorefresh_status & BIT(7)) && !iris_is_dual_supported()) { +#else + if (!(autorefresh_status & BIT(7))) { +#endif + 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); + } + + 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) { +#if defined(CONFIG_PXLW_IRIS) + if (iris_is_chip_supported()) { + atomic_inc(&cmd_enc->autorefresh.kickoff_cnt); + _sde_encoder_phys_cmd_config_autorefresh(phys_enc, frame_cnt); + goto end; + } +#endif + _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); + } + +#if defined(CONFIG_PXLW_IRIS) +end: +#endif + + /* 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 100755 index 000000000000..54faa7cb5cb6 --- /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 100755 index 000000000000..66248604a187 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys_wb.c @@ -0,0 +1,1935 @@ +// 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 void _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; + + phys_enc->in_clone_mode = false; + + /* Check if WB has CWB support */ + if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB))) + return; + + /* 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) { + phys_enc->in_clone_mode = true; + break; + } + } + + SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode); +} + +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 = phys_enc->in_clone_mode; + + _sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state); + + if (clone_mode_curr && !phys_enc->in_clone_mode) { + SDE_ERROR("WB commit before CWB disable\n"); + return -EINVAL; + } + + 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 100755 index 000000000000..eb9b8fb51dec --- /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 100755 index 000000000000..10177eecbb62 --- /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 100755 index 000000000000..19206f4a227a --- /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 100755 index 000000000000..3c47172b8765 --- /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 100755 index 000000000000..4a2b73f1ee10 --- /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 100755 index 000000000000..26585a2dbe49 --- /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 100755 index 000000000000..fe7077f3b1f7 --- /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 100755 index 000000000000..ad7aa05e1eb7 --- /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 100755 index 000000000000..bed02d96fbde --- /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 100755 index 000000000000..fe5d8e40223b --- /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 100755 index 000000000000..df25ce8df2e8 --- /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 100755 index 000000000000..d49280baaa4c --- /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 100755 index 000000000000..104aaf521b69 --- /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 100755 index 000000000000..f266683a96ea --- /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 100755 index 000000000000..3df8f8bc6b9f --- /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 100755 index 000000000000..47f405d36eb0 --- /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 100755 index 000000000000..e7920320fab2 --- /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 100755 index 000000000000..f65e3291c50d --- /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 100755 index 000000000000..a06b52b24f17 --- /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 100755 index 000000000000..0c90f1156232 --- /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 100755 index 000000000000..0dc1cbf8a3a6 --- /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 100755 index 000000000000..e5b0ab899703 --- /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 100755 index 000000000000..1e07b470c19a --- /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 100755 index 000000000000..33987c146537 --- /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 100755 index 000000000000..5b66b83be806 --- /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 100755 index 000000000000..dfc2ff1e4927 --- /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 100755 index 000000000000..5616d1f28631 --- /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 100755 index 000000000000..2be78655cc04 --- /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 100755 index 000000000000..f6ac49701657 --- /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 100755 index 000000000000..403ac6b286b1 --- /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 100755 index 000000000000..3be559bc1011 --- /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 100755 index 000000000000..07574d3f656d --- /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 100755 index 000000000000..a5384a5f981a --- /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 100755 index 000000000000..79a0b807333d --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_pingpong.c @@ -0,0 +1,577 @@ +// 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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, 0, 0, 1, 2 +}; + +#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; +} +extern int op_dither_enable; + +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; +#if defined(CONFIG_PXLW_IRIS) + iris_sde_update_dither_depth_map(dither_depth_map); +#endif + 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); + } + if (op_dither_enable==1){ + SDE_REG_WRITE(c, base, 1); + }else{ + SDE_REG_WRITE(c, base, 0); + } + + 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 100755 index 000000000000..102cfc03afe8 --- /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 100755 index 000000000000..054ad76daf62 --- /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 100755 index 000000000000..00549dcbb176 --- /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 100755 index 000000000000..e8911cf80661 --- /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 100755 index 000000000000..828f18634926 --- /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 100755 index 000000000000..afed6e672934 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.c @@ -0,0 +1,3790 @@ +// 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); +} + +extern int op_dither_enable; +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], *data; + 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; + data = kzalloc((IGC_TBL_LEN + 1) * sizeof(u32), GFP_KERNEL); + if (!data) { + DRM_ERROR("unable to allocate buffer\n"); + return; + } + + 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; + } + + memcpy(data, addr[i], IGC_TBL_LEN * sizeof(u32)); + data[IGC_TBL_LEN] = data[IGC_TBL_LEN - 1]; + REG_DMA_SETUP_OPS(dma_write_cfg, offset, data, + (IGC_TBL_LEN + 1) * 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); + kfree(data); + return; + } + } + + kfree(data); + 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) { + if (op_dither_enable==1){ + reg = lut_cfg->strength & IGC_DITHER_DATA_MASK; + //reg=6; + } + else{ + reg =0; + } + 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; + } + } + + if (op_dither_enable==1){ + reg = IGC_EN; + } + else{ + reg = IGC_EN|BIT(1); + } + + 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 100755 index 000000000000..cad0787ec473 --- /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 100755 index 000000000000..7184807fc241 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_sspp.c @@ -0,0 +1,1408 @@ +// 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" +#if defined(PXLW_IRIS_DUAL) +#include "iris/dsi_iris5_api.h" +#endif + +#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; +} + +#if defined(PXLW_IRIS_DUAL) +int iris_sspp_subblk_offset(struct sde_hw_pipe *ctx, int s_id, u32 *idx) +{ + return _sspp_subblk_offset(ctx, s_id, idx); +} +#endif +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); +} + +#if defined(PXLW_IRIS_DUAL) +static void sde_hw_sspp_setup_csc_v2(struct sde_hw_pipe *ctx, + const struct sde_format *fmt, struct sde_csc_cfg *data) +{ + return iris_sde_hw_sspp_setup_csc_v2(ctx, fmt, data); +} +#endif +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)) +#if defined(PXLW_IRIS_DUAL) + { +#endif + c->ops.setup_csc = sde_hw_sspp_setup_csc; +#if defined(PXLW_IRIS_DUAL) + c->ops.setup_csc_v2 = sde_hw_sspp_setup_csc_v2; + } +#endif + + 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 100755 index 000000000000..35883f4712d2 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_sspp.h @@ -0,0 +1,678 @@ +/* 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); + +#if defined(PXLW_IRIS_DUAL) + /** + * setup_csc_v2 - setup color space conversion version 2 + * @ctx: Pointer to pipe context + * @fmt: Pointer to sde_format structure + * @data: Pointer to config structure + */ + void (*setup_csc_v2)(struct sde_hw_pipe *ctx, + const struct sde_format *fmt, + struct sde_csc_cfg *data); +#endif + /** + * 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 100755 index 000000000000..b02cd17cbb28 --- /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 100755 index 000000000000..21f1daf1098f --- /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 100755 index 000000000000..f1a8a8b1f78e --- /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 100755 index 000000000000..a0b692b83e7e --- /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 100755 index 000000000000..ff4b5dfd08f0 --- /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 100755 index 000000000000..84b16336c591 --- /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 100755 index 000000000000..e5c089f83b48 --- /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 100755 index 000000000000..826b126a60b1 --- /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 100755 index 000000000000..8fbf394612a6 --- /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 100755 index 000000000000..a6c95cc5ebba --- /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 100755 index 000000000000..c3dbde0f2ada --- /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 100755 index 000000000000..e8574156512e --- /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 100755 index 000000000000..9a23873903ef --- /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 100755 index 000000000000..17073724e6d7 --- /dev/null +++ b/techpack/display/msm/sde/sde_kms.c @@ -0,0 +1,3890 @@ +/* + * 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" +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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, rc; + + 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"); +retry: + /* attempt to acquire ww mutex for connection */ + rc = drm_modeset_lock(&old_state->dev->mode_config.connection_mutex, + old_state->acquire_ctx); + + if (rc == -EDEADLK) { + drm_modeset_backoff(old_state->acquire_ctx); + goto retry; + } + + /* 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 sde_kms *sde_kms; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return false; + } + + sde_kms = to_sde_kms(kms); + return sde_kms->splash_data.num_splash_displays; +} + +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, +#if defined(CONFIG_PXLW_IRIS) || defined(CONFIG_PXLW_SOFT_IRIS) + .iris_operate = iris_sde_kms_iris_operate, +#endif +}; + +/* 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 100755 index 000000000000..50a4de5fb986 --- /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 5000 + +/** + * 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 100755 index 000000000000..7bb2445e2ba5 --- /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 100755 index 000000000000..7a1b8b19f716 --- /dev/null +++ b/techpack/display/msm/sde/sde_plane.c @@ -0,0 +1,4653 @@ +/* + * 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" +#if defined(CONFIG_PXLW_IRIS) +#include "iris/dsi_iris5_api.h" +#endif + +#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; + + if (!plane || !fb) { + SDE_ERROR("invalid arguments\n"); + return; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + + 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)) + 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; + +#if defined(CONFIG_PXLW_IRIS) + iris_sde_plane_setup_csc(psde->csc_ptr); +#endif + 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; +} + +//xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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); +#if defined(PXLW_IRIS_DUAL) + if (psde->pipe_hw->ops.setup_csc_v2) + psde->pipe_hw->ops.setup_csc_v2(psde->pipe_hw, + fmt, psde->csc_usr_ptr); +#endif +} + +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); + + //xiaoxiaohuan@OnePlus.MultiMediaService,2018/08/04, 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 100755 index 000000000000..316bd75f47d9 --- /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 100755 index 000000000000..cd8568d606b0 --- /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 100755 index 000000000000..1454e41457b3 --- /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 100755 index 000000000000..7f3716b8bf28 --- /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 100755 index 000000000000..a397b0dc35dc --- /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 100755 index 000000000000..fbfa9aa552b0 --- /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 100755 index 000000000000..2dd7d3e2700f --- /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 100755 index 000000000000..b16e0c757cdb --- /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 100755 index 000000000000..4fcc2c316d3d --- /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 100755 index 000000000000..51f63d955c30 --- /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 100755 index 000000000000..6178e1bf1696 --- /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 100755 index 000000000000..e336f3236978 --- /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 100755 index 000000000000..71ec32830d62 --- /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 100755 index 000000000000..0fc473da9f87 --- /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 100755 index 000000000000..6501f329d57f --- /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 100755 index 000000000000..f449b04b3349 --- /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 100755 index 000000000000..538ef0b655ce --- /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 100755 index 000000000000..dbb56c40796b --- /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 100755 index 000000000000..3a525aefc393 --- /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 100755 index 000000000000..09649c59819a --- /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 100755 index 000000000000..9f66039966d5 --- /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 100755 index 000000000000..257c844d56ac --- /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 100755 index 000000000000..b6397a96508f --- /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 100755 index 000000000000..c624c868eeb6 --- /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 100755 index 000000000000..719962a3f627 --- /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 100755 index 000000000000..d3a589ccf301 --- /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 100755 index 000000000000..4779506a2814 --- /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 100755 index 000000000000..0b29a90caf87 --- /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 100755 index 000000000000..2ef735833002 --- /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 100755 index 000000000000..926723ff0769 --- /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 100755 index 000000000000..2adbdf3e66cb --- /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 100755 index 000000000000..4eb859c31922 --- /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 100755 index 000000000000..05641bb8432c --- /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 100755 index 000000000000..f8c9c3043bdf --- /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 100755 index 000000000000..8db4747d4ff2 --- /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 100755 index 000000000000..87037f9c60fa --- /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 100755 index 000000000000..4ce47a7f5497 --- /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 100755 index 000000000000..2a0ab26e7011 --- /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 100755 index 000000000000..35aa81494120 --- /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 100755 index 000000000000..3988de1248c5 --- /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 100755 index 000000000000..c1cb867f675f --- /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 100755 index 000000000000..abc08f639a57 --- /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 100755 index 000000000000..c089ecdf551c --- /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 100755 index 000000000000..f9e22c6abe25 --- /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 100755 index 000000000000..ba9052342d2a --- /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 100755 index 000000000000..16c2eff92e6b --- /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 100755 index 000000000000..2c59a6477f65 --- /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 100755 index 000000000000..6ec5a70b8322 --- /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 100755 index 000000000000..581fa3ba13b8 --- /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 100755 index 000000000000..963c56c06fb2 --- /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 100755 index 000000000000..94e16d86fd23 --- /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 100755 index 000000000000..8ce261caf3c3 --- /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 100755 index 000000000000..0769bf3061cb --- /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 100755 index 000000000000..b2053ec891f8 --- /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 100755 index 000000000000..03f6fa20ea80 --- /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 100755 index 000000000000..847ddf261a8b --- /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 100755 index 000000000000..962a4cec4984 --- /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 100755 index 000000000000..a0fba39c2c23 --- /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 100755 index 000000000000..04e93fd95042 --- /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 100755 index 000000000000..b4321df435f6 --- /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 100755 index 000000000000..5e0cd4cf4e7a --- /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 100755 index 000000000000..2f03d860ec72 --- /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 100755 index 000000000000..d847920c99c5 --- /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 100755 index 000000000000..e8c377267898 --- /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 100755 index 000000000000..d72ac73a8bbc --- /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 100755 index 000000000000..3cf850753aca --- /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 100755 index 000000000000..bdb319dc28a9 --- /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 100755 index 000000000000..66a6b5c03ab8 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_core.c @@ -0,0 +1,3586 @@ +// 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/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] = shm.size; + } 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 100755 index 000000000000..f9ce3350dc97 --- /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 100755 index 000000000000..0ef5192bc844 --- /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 100755 index 000000000000..8b988ff3083c --- /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 100755 index 000000000000..bdb9c57376ce --- /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 100755 index 000000000000..711d8d87b80b --- /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 100755 index 000000000000..56c51e9ae901 --- /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 100755 index 000000000000..71fa47b1caeb --- /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 100755 index 000000000000..2ef6cf7dabb7 --- /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 100755 index 000000000000..809a7d0f9a19 --- /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 100755 index 000000000000..3fe1de7f2984 --- /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 100755 index 000000000000..f78ba0fb87e7 --- /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 100755 index 000000000000..c7234e505e08 --- /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 100755 index 000000000000..a56b389fc9fe --- /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 100755 index 000000000000..fdc44f5bb956 --- /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 100755 index 000000000000..06bc11c3cdd5 --- /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 100755 index 000000000000..0d75e2f94c14 --- /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 100755 index 000000000000..14b3507eeeba --- /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 100755 index 000000000000..b5356609c464 --- /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 100755 index 000000000000..5c6cb2c5cce1 --- /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 100755 index 000000000000..5de8e8b3d381 --- /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 100755 index 000000000000..0d36bd549c43 --- /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 100755 index 000000000000..de7b6139b445 --- /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 100755 index 000000000000..d2060afb0fae --- /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 100755 index 000000000000..eef53979fbb2 --- /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 100755 index 000000000000..70a5206979cf --- /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 100755 index 000000000000..7d99fd9ed43b --- /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 100755 index 000000000000..14669fdf4097 --- /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 100755 index 000000000000..e0c666f91b6d --- /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 100755 index 000000000000..a4f28cfe05c8 --- /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 100755 index 000000000000..55dbd0732ad2 --- /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 100755 index 000000000000..307cee86f530 --- /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 100755 index 000000000000..0dcb2413fc02 --- /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 100755 index 000000000000..85998200d7a2 --- /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 100755 index 000000000000..c7b671f3df87 --- /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 100755 index 000000000000..0235ce884458 --- /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 100755 index 000000000000..efb4eedfb73e --- /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 100755 index 000000000000..78d6c57a6920 --- /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 100755 index 000000000000..efb4eedfb73e --- /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 100755 index 000000000000..da305d52ecd1 --- /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 100755 index 000000000000..efb4eedfb73e --- /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 100755 index 000000000000..78d6c57a6920 --- /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 100755 index 000000000000..d0544d5c6a55 --- /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 100755 index 000000000000..6a28ed839f68 --- /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 100755 index 000000000000..55f3f5ee9247 --- /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 100755 index 000000000000..db709a0d0281 --- /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 100755 index 000000000000..7728d8e6d8a5 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_common.c @@ -0,0 +1,4945 @@ +// 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; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + mutex_lock(&device->lock); + 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); + 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 100755 index 000000000000..9d288c1a19f2 --- /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 100755 index 000000000000..1adc50d38e9d --- /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 100755 index 000000000000..f7d2c19e379c --- /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 100755 index 000000000000..179fb2abaefb --- /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 100755 index 000000000000..27cd92c17c70 --- /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 100755 index 000000000000..95278637bd0b --- /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 100755 index 000000000000..c46b15ff9983 --- /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 100755 index 000000000000..48efca59d755 --- /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 100755 index 000000000000..1a6f4ce63476 --- /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 100755 index 000000000000..33e89fbf7b17 --- /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 100755 index 000000000000..f7428e4fb9e9 --- /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 100755 index 000000000000..5f1602aca410 --- /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 100755 index 000000000000..0fd761e87343 --- /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 100755 index 000000000000..54923e18b3a0 --- /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 100755 index 000000000000..d2e8b28033ed --- /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 100755 index 000000000000..0ad13a833435 --- /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 100755 index 000000000000..a9ff51824eba --- /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 100755 index 000000000000..cbb46852cbb9 --- /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 100755 index 000000000000..7fb249184c13 --- /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 100755 index 000000000000..c7af4a276421 --- /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 100755 index 000000000000..a94bc485e32b --- /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 100755 index 000000000000..fd81eef11d5e --- /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 100755 index 000000000000..d98592703d6c --- /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 100755 index 000000000000..91c1f6f2ec69 --- /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 100755 index 000000000000..0da868b57612 --- /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 100755 index 000000000000..5fdfe530d608 --- /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 100755 index 000000000000..7515a4b49d68 --- /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 100755 index 000000000000..21adfe4d560e --- /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 100755 index 000000000000..1c64e3ceeef9 --- /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 100755 index 000000000000..e803269aa6bd --- /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 100755 index 000000000000..7ddc7be76378 --- /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 100755 index 000000000000..8fdbf3434fca --- /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 100755 index 000000000000..56f8d0e08e57 --- /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 100755 index 000000000000..1b9e9942cb44 --- /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 100755 index 000000000000..5254d2900c07 --- /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 100755 index 000000000000..6e1f46f095bc --- /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 100755 index 000000000000..111965e6e457 --- /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 100755 index 000000000000..5fd937757e50 --- /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 100755 index 000000000000..212b227b1821 --- /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 100755 index 000000000000..1448d4aad561 --- /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